2011-04-29 3 views
6

Mi ricordo una volta di andare a vedere [Srinivasa Ramanujan] quando era malato a Putney. Avevo cavalcato in taxi numero numero 1729 e ho osservato che il numero mi sembrava piuttosto noioso, e che speravo non fosse un presagio sfavorevole . "No," rispose, "è un numero molto interessante: è il numero più piccolo che è espresso come la somma di due cubi in due modi diversi ". [G. H. Hardy, come detto in "1729 (number)"]Trova il numero di Hardy-Ramanujan usando lo schema R5RS. Si prega di suggerire miglioramenti nell'idioma e nei calcoli.

In "Math Wrath" Joseph Tartakovsky dice di questa impresa, "E allora? Dammi due minuti e il mio orologio calcolatrice, e io farò lo stesso senza esercitare alcuna po 'grigia cellule ". Non so come il Tartakovsky realizzasse tale prova su un orologio da calcolatrice, ma il seguente è la mia funzione di schema che enumera i numeri che iniziano a a 1 e si ferma quando trova un numero che è espressivo in due modi separati da sommando i cubi di due numeri positivi. Ed è restituisce 1729.

Ci sono due aree in cui vorrei apprezzare i suggerimenti per il miglioramento . Un'area è, essendo nuovo per lo schema, lo stile e l'idioma. L'altra area è intorno ai calcoli. SISC non restituisce i numeri esatti per le radici, anche quando potrebbero essere. Ad esempio, (expt 27 1/3) cede 2,9999999999999996. Ma io capisco esatte retults quando cubatura un numero esatto, (expt 3 3) cede 27. La mia soluzione era quello di ottenere il pavimento esatta di una radice cubica e quindi verificare contro il cubo del pavimento e il cubo del pavimento più uno, contando come un fiammifero se uno partita. Questa soluzione sembra disordinata e difficile da ragionare. C'è un modo più diretto?

; 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)))))) 

risposta

6

il codice sia per lo più bene, vedo un paio di cose molto minori per commentare:

  • Non c'è bisogno di definire cube e cube-root presso il campo di applicazione più interno,

  • Utilizzo define per le funzioni interne fa sembrare un po 'più chiaro,

  • Questo è legato a la seconda parte della tua domanda: stai usando inexact->exact su un numero in virgola mobile che può portare a grandi razionali (nel senso che assegni una coppia di due grandi numeri interi) - sarebbe meglio evitare questo,

  • Facendo che ancora non risolve il test in più che si fa - ma questo è solo perché non siete certi se si ha il giusto numero di se ti sei perso di 1. Dato che dovrebbe essere vicino in un intero , si può semplicemente utilizzare round e quindi eseguire una verifica, risparmiando un test.

fissaggio quanto sopra, e farlo in una funzione che restituisce il numero quando viene trovata, e l'utilizzo di alcuni altri nomi identificatore "ovvie", ottengo questo:

(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)))))) 

sto correndo questo su Racket, e sembra che sia circa 10 volte più veloce (50ms contro 5ms).

+0

+1 per non sovrastare la soluzione. Inizialmente pensavo di scrivere una soluzione che ottimizzasse micro un paio di cose, ma la tua risposta è molto concisa, e ovviamente abbastanza veloce. Yay per semplicità! –

0

Diversi schemi si comportano in modo diverso quando si tratta di esponenziazione esatta: alcuni restituiscono un risultato esatto quando possibile, alcuni un risultato inesatto in tutti i casi. Puoi guardare ExactExpt, una delle mie pagine implementation contrasts, per vedere quali Schemi fanno cosa.