Common lisp 大N.Common Lisp的代码结果不正确

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)) )

下面的代码给出了错误的答案。它应该给出大约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))
        )
        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:不要用悬空的括号。学习使用缩进代码并显示相应括号的编辑器。代码将更加紧凑和可读。当括号之间有一定距离时,你的眼睛和大脑无论如何都无法看到哪个括号对齐。编辑可以很容易地显示它。