这是 question on double-float 的后续内容我之前发布的。对于这可能是 Lisp 的基本概念,我深表歉意,但我还没有掌握它。
对于这个问题,我使用GNU CLISP 2.49 (2010-07-07)
。
假设我有以下函数,它只是通过牛顿法确定平方根:
(defun sr (n eps)
(when (>= n 0)
(do ((x (/ n 2.0) (/ (+ x (/ n x)) 2.0)))
((< (abs (- (* x x) n)) eps)
x))))
我可以这样调用它:
> (sr 2 0.00001)
1.4142157
它给了我单精度 float (默认值)。说得通。由于缺乏精度,如果我将 eps 设得太小,它就无法正常运行并进入无限循环:
> (sr 2 0.00000001)
[just sits there...]
如果我用 double 值调用它,我仍然得到单精度结果:
> (sr 2.0d0 0.00001d0)
1.4142157
> (sr 2.0d0 0.00000001d0)
[just sits there...]
但是如果我按如下方式重新定义我的函数:
(defun sr (n eps)
(when (>= n 0)
(do ((x (/ n 2.0d0) (/ (+ x (/ n x)) 2.0d0)))
((< (abs (- (* x x) n)) eps)
x))))
然后,无论我如何提供它,我都会得到 double :
> (sr 2 0.00001)
1.4142156862745097d0
现在由于精度提高,可以给它提供更小的eps
:
> (sr 2 0.00000001)
1.4142135623746899d0
所以我的问题是:函数应用的精度完全由我在它包含的算术表达式中使用的常量中指定的精度驱动吗?如果是这样,如果函数中没有常量怎么办?那么什么决定了计算和结果的精度呢?
附录
我刚刚在 SBCL 1.0.57-1.fc17
上重新测试了这一点,根据 @JoshuaTaylor 在评论中引用的文档,我得到了更多预期结果。
最佳答案
在我看来,CLISP 与 ANSI CL 标准不兼容。
ANSI CL 标准要求结果是所有参数中最大的类型:
CL-USER 20 > (/ 2.0d0 2.0)
1.0D0
CLISP 给出:
[4]> (/ 2.0d0 2.0)
1.0
这应该是一个双 float 。
您可以在 CLISP 中将其更改为标准 ANSI CL 行为:
[9]> CUSTOM:*FLOATING-POINT-CONTAGION-ANSI*
NIL
[10]> (setf CUSTOM:*FLOATING-POINT-CONTAGION-ANSI* t)
T
[11]> (sr 2.0d0 0.00001d0)
1.4142156862745097d0
现在它返回了所需的结果。
请参阅 CLISP 手册:12.2.4.1. Rule of Float Precision Contagion
关于lisp - 了解函数中的数字数据类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21356845/