这是我之前发布的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
它给了我单精度浮点数(默认值)。说得通。由于缺乏精确性,如果我使eps
太小,它就无法正常运行并进入无限循环:
> (sr 2 0.00000001)
[just sits there...]
如果我用双精度值调用它,我仍然得到单精度结果:
> (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))))
无论我如何喂它,我都会得到双精度:
> (sr 2 0.00001)
1.4142156862745097d0
由于精度提高,现在为它提供较小的eps
作品:
> (sr 2 0.00000001)
1.4142135623746899d0
所以我的问题是:函数应用的精度是否完全由我在其包含的算术表达式中使用的常量中指定的精度驱动?如果是这样,如果函数中没有任何常量怎么办?那么什么决定了计算的精确度和结果呢?
<小时/> 的附录
根据@JoshuaTaylor在评论中引用的文档,我在SBCL 1.0.57-1.fc17
上重新测试了这一点,并得到了更多预期的结果。
答案 0 :(得分:4)
在我看来,这是CLISP与ANSI CL标准的不兼容。
ANSI CL标准要求结果是所有参数的最大类型:
CL-USER 20 > (/ 2.0d0 2.0)
1.0D0
CLISP给出:
[4]> (/ 2.0d0 2.0)
1.0
这应该是双浮动。
您可以在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