这是我之前发布的关于双浮的问题的后续内容。我为可能是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因此,我的问题是:函数应用的精度是否完全取决于它在其包含的算术表达式中所使用的常量中指定的精度?如果是的话,如果函数中没有常量呢?那么是什么决定了计算和结果的精度呢?
增编
我刚刚在SBCL 1.0.57-1.fc17上重新测试了这一点,根据@JoshuaTaylor在评论中引用的文档,我得到了更多预期的结果。
发布于 2014-01-25 22:12:13
在我看来,这是CLISP与ANSI CL标准的不兼容。
ANSI CL标准要求结果是所有参数中最大的类型:
CL-USER 20 > (/ 2.0d0 2.0)
1.0D0CLISP给出:
[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.浮子精密接触规则
https://stackoverflow.com/questions/21356845
复制相似问题