【发布时间】:2017-11-19 17:26:32
【问题描述】:
对于另一个 Project Euler 斗争(使用 SBCL 1.3.17),我想测试一个数字是否为 pentagonal number。如果
的结果,这可以很容易地测试(/ (+ 1 (sqrt (+ 1 (* 24 number)))) 6)
是一个自然数。忽略一个自然数不仅仅是一个整数,因为number 将只有正值,我开始使用intergerp 作为谓词,但它不适用于所有测试的数字。所以我想出了以下内容:
(defun is-pentagonal-p (number)
"Returns T if NUMBER is a pentagonal number."
(multiple-value-bind (n m)
(floor (/ (+ 1 (sqrt (+ 1 (* 24 number)))) 6))
(declare (ignore n))
(when (zerop m) t)))
对于简单的例子来说效果很好,即低数字,但对于 1533776805 这样的高数字又失败了。过了一会儿,我想起了我以前的 Fortran 日子,结果是:
(defun is-pentagonal-p (number)
"Returns T if NUMBER is a pentagonal number."
(multiple-value-bind (n m)
(floor (/ (+ 1.0d0 (sqrt (+ 1.0d0 (* 24.0d0 number)))) 6.0d0))
(declare (ignore n))
(when (zerop m) t)))
它显式地降低了舍入误差并给出了正确的结果,但让我觉得我一定错过了一些更简单、更简洁的东西。这只是偏执狂吗?
【问题讨论】:
-
is-<...>-p是 Lisp 风格的-p后缀和 C/Java 风格的is前缀的组合。它会震动双方人群的审美感受。 -
@sds 我不知道这个问题。我不记得为什么我开始对谓词使用这种命名方案。我绝对不想打扰你的审美!
-
在我的解决方案中,我使用了
(defun pentap(x) (subtypep (type-of (/ (1+ (sqrt (1+ (* x 24)))) 6)) 'integer)),(有效),但我不知道这是否是最好的测试......(或者即使它真的正确!)。跨度> -
@Renzo:这是重新实现
integerp的一种非常有创意的方式:-) -
@sds,很可能,当时我在至少 35 年后开始重新使用 lisp! :)
标签: floating-point integer common-lisp precision