Find the Hardy-Ramanujan number using the R5RS circuit. Please suggest improvements in idiom and calculations.

I remember one day I will see [Srinivasa Ramanujan] when he fell ill in Putni. I rode in taxi number 1729 and noted that the number seemed rather boring to me, and I hoped that this was not an unfavorable omen. β€œNo,” he replied, β€œthis is a very interesting number, this is the smallest number expressed as the sum of two cubes in two different ways.” [G. H. Hardy, as stated in "1729 (Number)" ]

In "Math Wrath," Joseph Tartakovsky says of this feat: "So what? Give me two minutes and the clock of my calculator, and I will do the same without any small gray cells." I don’t know how Mr. Tartakovsky will execute this proof on a calculator, but my next function is a scheme that lists numbers starting with 1 and stops when it finds a number that is expressed in two separately, summing the cubes of two positive numbers. And that really returns 1729.

There are two areas where I would appreciate an improvement. One area, being new to scheme, style, and idiom. Another area around calculations. SISC does not return exact numbers for roots, even when they may be. For example (expt 27 1/3) gives 2.999999999999999996. But I repeat exactly when cubing the exact number, (expt 3 3) gives 27 . my solution was to get the exact floor of the cube root and then check against the floor cube and the floor cube plus one, considering it a coincidence if they match. This decision seems erratic and intractable. Is there an easier way?

 ; 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)))))) 
+6
source share
2 answers

Your code looks mostly beautiful, I see a few very small things to comment on:

  • There is no need to define cube and cube-root in the innermost area,

  • Using define for internal functions makes it a little understandable,

  • This is related to the second part of your question: you use inexact->exact respect to the floating point number, which can lead to large rational ones (in the sense that you are highlighting a pair of two large integers) - it would be better to avoid this,

  • Doing this still will not solve the extra test that you do, but this is only because you are not sure that you have the right number, if you missed 1. Given that it should be close to an integer, you can just use round , and then do one test, saving one test.

Correcting the above and executing it in one function, which returns the number when it is found, and using some more "obvious" identifier names, I get the following:

 (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 (- ni^3)))] [count (if (= n (+ i^3 j^3)) (+ count 1) count)]) (if (= count 2) n (iter (+ i 1) count)))))) 

I run this on Racket and it looks about 10 times faster (50 ms vs 5 ms).

+6
source

Different schemes behave differently when it comes to precise exponentiation: some return an accurate result when possible, some inaccurate results in all cases. You can look at ExactExpt , one of my implementation contrasts , to see which schemes do what.

0
source

Source: https://habr.com/ru/post/886988/


All Articles