Найдите число Харди-Рамануджана, используя схему R5RS. Пожалуйста, предложите улучшения в идиомах и расчетах.

Я помню, как однажды увидим [Шриниваса Рамануджан], когда он был болен в Патни. Я ехал в такси номер 1729 и отметил, что номер показался мне довольно скучным., и я надеялся, что это не было неблагоприятное предзнаменование. - Нет, - ответил он, - это очень интересное число. наименьшее число выражаются сумма двух кубов в двух разных пути."[Г. Х. Харди, как сказано в "1729 (номер)"]

In "Математика Гнева" Жозеф Тартаковский говорит об этом подвиге: "ну и что? Дай мне две минуты и часы с калькулятором, и я сделаю то же самое. без каких-либо маленьких серых клеток."Я не знаю, как Г - н Тартаковский выполнил бы это доказательство на часах калькулятора, но ниже приведена моя функция схемы, которая перечисляет начальные числа на 1 и останавливается, когда находит число, expressable в два разными путями путем суммирования кубов двух положительных чисел. И это возвращает indeeds 1729.

есть две области, где я был бы признателен за предложения для улучшение. Одна из областей-быть новым для схемы, стиля и идиомы. Другая область - вокруг расчетов. Sisc не возвращает точных чисел для корней, даже когда они могли бы быть. Для пример (expt 27 1/3) дает 2.999999999999999996. Но я вам точно retults когда кубатуры точное число, (expt 3 3) доходность 27. Мой решение состояло в том, чтобы получить точный пол кубического корня, а затем проверить против Куба и кубик пола плюс один, считается матч, если матч. Это решение кажется запутанным и трудным для рассуждений. Есть ли более простой способ?

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

2 ответов


ваш код выглядит в основном нормально, я вижу несколько очень незначительных вещей, чтобы прокомментировать:

  • нет необходимости определять cube и cube-root в самой сокровенной области,

  • используя define для внутренних функций делает его выглядеть немного яснее,

  • это связано со второй частью вашего вопроса: Вы используете inexact->exact на число с плавающей запятой, которое может привести к большим рациональным (в том смысле, что вы выделяете пара двух больших целых чисел) -- лучше этого избежать,

  • это все еще не решает дополнительный тест, который вы делаете, но это только потому, что вы не уверены, есть ли у вас правильное число, если вы пропустили на 1. Учитывая, что это должно быть закрыть в целое число, вы можете просто использовать round а затем выполните одну проверку, сохранив один тест.

фиксировать вышеуказанное, и делать его в одной функции которая возвращает номер когда он найден, и, используя еще несколько "очевидных" имен идентификаторов, я получаю следующее:

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

я запускаю это на ракетке, и похоже, что это примерно в 10 раз быстрее (50 мс против 5 мс).


различные схемы ведут себя по-разному, когда дело доходит до точного возведения в степень: некоторые возвращают точный результат, когда возможно, некоторые неточный результат во всех случаях. Вы можете посмотреть ExactExpt один из моих набор контрасты реализации страницы, чтобы увидеть, какие схемы делать.