Common lisp 大N.Common Lisp的代码结果不正确
下面的代码给出了错误的答案。它应该给出大约0.5,这是在0和1之间有许多随机数的数组的平均值。我认为问题是因为N是“到大”,或者可能是生成的随机数的精度?。该代码适用于较小的N值(10^7、10^6等)。一些建议会有帮助 先谢谢你Common lisp 大N.Common Lisp的代码结果不正确,common-lisp,precision,floating-accuracy,Common Lisp,Precision,Floating Accuracy,下面的代码给出了错误的答案。它应该给出大约0.5,这是在0和1之间有许多随机数的数组的平均值。我认为问题是因为N是“到大”,或者可能是生成的随机数的精度?。该代码适用于较小的N值(10^7、10^6等)。一些建议会有帮助 先谢谢你 (defun randvec(n) (let ((arr (make-array n))) (dotimes (i n) (setf (aref arr i) (random 1.0)) )
(defun randvec(n)
(let ((arr (make-array n)))
(dotimes (i n)
(setf (aref arr i) (random 1.0))
)
arr
)
)
(defparameter N (expt 10 8))
(setf *random-state* (make-random-state t))
(defparameter vector1 (randvec N))
(format t "~a~%" (/ (reduce #'+ vector1) (length vector1)))
浮点数的精度 您正在使用单精度浮点数进行计算。将所有随机数相加,得到一个浮点数。您添加的数字越多,浮动将越大。这最终会导致您的结果不够精确 像
1.0d0
这样的双浮点数比像1.0s0
这样的单浮点数具有更高的精度。默认情况下,1.0
读取为单个浮点<代码>(随机1.0d0)将计算双浮点
(defun randvec (n)
(let ((v (make-array n)))
(dotimes (i n v)
(setf (aref v i) (random 1.0d0))))) ; create a double float random number
(defun test (&optional (n 10))
(setf *random-state* (make-random-state t))
(let ((v (randvec n)))
(/ (reduce #'+ v) (length v))))
例如:
CL-USER 58 > (test (expt 10 8))
0.4999874882753848D0
风格
使用common Lisp编程时,请使用common Lisp编程风格:
- 如果没有必要,不要使用全局变量。改为使用局部变量编写函数
- 如果使用
定义全局变量,请不要将其命名为defparameter
,而应命名为n
*n*
- 正确格式化和缩进代码。缩进应该在编辑器帮助下完成
- 不要在自己的行中使用括号
请参阅上面的示例。浮点数的精度 您正在使用单精度浮点数进行计算。将所有随机数相加,得到一个浮点数。您添加的数字越多,浮动将越大。这最终会导致您的结果不够精确 像
1.0d0
这样的双浮点数比像1.0s0
这样的单浮点数具有更高的精度。默认情况下,1.0
读取为单个浮点<代码>(随机1.0d0)将计算双浮点
(defun randvec (n)
(let ((v (make-array n)))
(dotimes (i n v)
(setf (aref v i) (random 1.0d0))))) ; create a double float random number
(defun test (&optional (n 10))
(setf *random-state* (make-random-state t))
(let ((v (randvec n)))
(/ (reduce #'+ v) (length v))))
例如:
CL-USER 58 > (test (expt 10 8))
0.4999874882753848D0
风格
使用common Lisp编程时,请使用common Lisp编程风格:
- 如果没有必要,不要使用全局变量。改为使用局部变量编写函数
- 如果使用
定义全局变量,请不要将其命名为defparameter
,而应命名为n
*n*
- 正确格式化和缩进代码。缩进应该在编辑器帮助下完成
- 不要在自己的行中使用括号
请看我上面的例子。错别字道歉,我指的是0和1;“太大”是数值分析中精度失败的一个经典例子——添加不同比例的数字。将每个数字除以/before/adding,取而代之-然后你将添加相同比例的数字;“太大”是数值分析中精度失败的一个经典例子——添加不同比例的数字。将每个数字除以/before/adding,取而代之-然后您将添加相同比例的数字。非常感谢。另外,感谢您对lisp编程风格的建议。关于括号在他们自己的行中的使用,我使用它是因为它给了我清晰的含义,我还看到一些关于lisp的书籍使用它(例如Robin Jones Clive Maynard Ian Stewart的lisp编程艺术)。虽然有点老了。@Francisco:不要用悬空的括号。学习使用缩进代码并显示相应括号的编辑器。代码将更加紧凑和可读。当括号之间有一定距离时,你的眼睛和大脑无论如何都无法看到哪个括号对齐。编辑可以很容易地展示出来。非常感谢。另外,感谢您对lisp编程风格的建议。关于括号在他们自己的行中的使用,我使用它是因为它给了我清晰的含义,我还看到一些关于lisp的书籍使用它(例如Robin Jones Clive Maynard Ian Stewart的lisp编程艺术)。虽然有点老了。@Francisco:不要用悬空的括号。学习使用缩进代码并显示相应括号的编辑器。代码将更加紧凑和可读。当括号之间有一定距离时,你的眼睛和大脑无论如何都无法看到哪个括号对齐。编辑可以很容易地显示它。