使用R5RS方案查找Hardy-Ramanujan数字。请提出成语和计算方面的改进建议。

时间:2011-04-29 23:55:04

标签: scheme

  

我记得有一次会去看   [Srinivasa Ramanujan]生病时   在普特尼。我乘坐出租车   号码1729,并评论说   在我看来,数字相当沉闷,   我希望它不是一个   不利的预兆。 “不,”他回答说,   “这是一个非常有趣的数字;它   是可表达的最小数字   两个不同的立方体的总和   方式。“[G. H. Hardy在"1729 (number)"中说道]

"Math Wrath"约瑟夫·塔尔塔科夫斯基谈到这一壮举,“那又怎样? 给我两分钟和我的计算器表,我也会这样做 没有施加任何小灰色细胞。“我不知道怎么做 Tartakovsky先生将在计算器手表上完成这一证明,但是 以下是我的计划函数,它枚举数字开头 在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 个答案:

答案 0 :(得分:6)

你的代码看起来很好,我看到一些非常小的评论内容:

  • 无需在最里层范围内定义cubecube-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倍(50ms vs 5ms)。

答案 1 :(得分:0)

当涉及精确取幂时,不同的方案表现不同:一些在可能的情况下返回一个精确的结果,一些在所有情况下都是不精确的结果。您可以查看我ExactExpt页面中的一个implementation contrasts,了解哪些方案可以执行哪些操作。