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

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

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

Есть две области, где я буду признателен за предложения улучшение. Одной из областей является новизна схемы, стиля и идиомы. Другая область вокруг расчетов. SISC не возвращает точные числа для корней, даже если они могут быть. За пример (expt 27 1/3) дает 2.9999999999999996. Но я точно повторяет при кубировании точного числа, (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 ]

6 голосов
/ 30 апреля 2011

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

  • Нет необходимости определять 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))))))

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

0 голосов
/ 20 сентября 2015

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...