2011-04-29 7 views
6

Pamiętam, jak pewnego razu zobaczyłem [Śrinivasa Ramanujana], kiedy on był chory w Putney. Jeździłem taksówką numer numer 1729 i zauważyłem, że numer wydawał mi się raczej nudny, i że miałem nadzieję, że nie był to niekorzystny omen . "Nie", odpowiedział, "jest to bardzo ciekawa liczba, to jest jest najmniejszą liczbą wyrażającą się jako sumą dwóch kostek na dwa różne sposoby ." [SOL. H. Hardy jak powiedział w "1729 (number)"]Znajdź numer Hardy-Ramanujana za pomocą schematu R5RS. Proszę sugerować ulepszenia idiomu i obliczeń.

W "Math Wrath" Joseph Tartakovsky mówi o tym wyczyn, „Więc co? Daj mi dwie minuty i mój kalkulator zegarek, a ja to samo bez wywierania jakiegokolwiek szarych komórki." Nie wiem, jak pan Tartakovsky wykonałby ten dowód na zegarku kalkulatora, ale poniżej jest funkcja mojego schematu, która wylicza liczby rozpoczynające się od na 1 i zatrzymuje się, gdy znajdzie numer, który można wyrazić w dwóch oddzielnych znakach przez sumując kostki dwóch liczb dodatnich. I to Rzeczywiście zwraca 1729.

Istnieją dwa obszary, w których chciałbym docenić propozycje poprawy . Jednym z obszarów jest bycie nowym w schemacie, stylu i idiomie. Drugi obszar jest wokół obliczeń. Sisc nie zwraca dokładnych liczb dla korzeni, nawet jeśli mogły być. Dla przykład (expt 27 1/3) daje 2,9999999999999996. Ale otrzymuję dokładne retransmisje , gdy sześcian o dokładnej liczbie, (expt 3 3), daje 27. Moim rozwiązaniem było uzyskanie dokładnego poziomu podstawy kostki, a następnie przetestowanie przeciwko kostce podłogi i kostce podłogi plus jedna, , licząc jako dopasowanie, jeśli pasują. To rozwiązanie wydaje się trudne i trudne do zrozumienia. Czy istnieje bardziej prosty sposób?

; Find the Hardy-Ramanujan number, which is the smallest positive 
; integer that is the sum of the cubes of two positivie integers in 
; two seperate ways. 
(define (hardy-ramanujan-number) 
    (let ((how-many-sum-of-2-positive-cubes 
      ; while i^3 + 1 < n/1 
      ;  tmp := exact_floor(cube-root(n - i^3)) 
      ;  if n = i^3 + tmp^3 or n = i^3 + (tmp + 1) ^3 then count := count + 1 
      ; return count 
      (lambda (n) 
      (let ((cube (lambda (n) (expt n 3))) 
        (cube-root (lambda (n) (inexact->exact (expt n 1/3))))) 
       (let iter ((i 1) (count 0)) 
       (if (> (+ (expt i 3) 1) (/ n 2)) 
        count 
        (let* ((cube-i (cube i)) 
          (tmp (floor (cube-root (- n cube-i))))) 
         (iter (+ i 1) 
         (+ count 
          (if (or (= n (+ cube-i (cube tmp))) 
            (= n (+ cube-i (cube (+ tmp 1))))) 
           1 
           0)))))))))) 
    (let iter ((n 1)) 
     (if (= (how-many-sum-of-2-positive-cubes n) 2) 
      n 
      (iter (+ 1 n)))))) 

Odpowiedz

6

Twój kod wygląda przeważnie w porządku, widzę kilka bardzo drobnych rzeczy do komentowania:

  • Nie ma potrzeby definiowania cube i cube-root w zakresie najgłębszej,

  • Używanie define dla funkcji wewnętrznych sprawia, że ​​wygląda nieco jaśniej,

  • Jest to związane z druga część pytania: używasz inexact->exact na liczbach zmiennoprzecinkowych, które mogą prowadzić do dużych racjonałów (w tym sensie, że przydzielasz parę dwóch dużych liczb całkowitych) - lepiej byłoby tego uniknąć,

  • Wykonanie tego nadal nie rozwiązuje dodatkowego testu, który wykonujesz - ale to tylko dlatego, że nie masz pewności, czy masz odpowiednią liczbę, jeśli pominąłeś o 1. Biorąc pod uwagę, że powinno być zamknij na liczbę całkowitą , możesz po prostu użyć round, a następnie wykonać jedną kontrolę, oszczędzając jeden test.

Mocowanie powyżej, i robi to w jednej funkcji, która zwraca liczbę, kiedy to znalazł, i korzystania z niektórych bardziej „oczywisty” nazwy identyfikatorów, otrzymuję to:

(define (hardy-ramanujan-number n) 
    (define (cube n) (expt n 3)) 
    (define (cube-root n) (inexact->exact (round (expt n 1/3)))) 
    (let iter ([i 1] [count 0]) 
    (if (> (+ (cube i) 1) (/ n 2)) 
     (hardy-ramanujan-number (+ n 1)) 
     (let* ([i^3 (cube i)] 
      [j^3 (cube (cube-root (- n i^3)))] 
      [count (if (= n (+ i^3 j^3)) (+ count 1) count)]) 
     (if (= count 2) n (iter (+ i 1) count)))))) 

biegnę to na Racket, i wygląda na to, że jest około 10 razy szybsze (50ms vs 5ms).

+0

+1 za niewystarczającą ekspansję rozwiązania. Pierwotnie planowałem napisać rozwiązanie, które zoptymalizowało mikroskopowo kilka rzeczy, ale twoja odpowiedź jest bardzo zwięzła i oczywiście wystarczająco szybko. Yay dla prostoty! –

0

Różne schematy zachowują się inaczej, jeśli chodzi o dokładną potęgowanie: niektóre zwracają dokładny wynik, gdy jest to możliwe, a niektóre są niedokładne we wszystkich przypadkach. Możesz spojrzeć na ExactExpt, jeden z moich zestawów stron implementation contrasts, aby zobaczyć, które Schematy robią co.

Powiązane problemy