使用lisp随机函数的奇怪行为

时间:2015-01-04 00:44:43

标签: random common-lisp

是否有人可以向我解释有关浮点数随机函数的以下行为以及如何摆脱这个:

CL-USER> (loop for i from 1 to 20 collect (* 0.1 (random 100)))        

;; with sbcl ...
(9.2 4.4 9.5 0.5 9.7 5.8 4.3 9.900001 3.7 6.8 2.6000001 9.5 1.6 8.900001 3.3 1.7 5.1 5.5 4.2000003 8.2)

;; with closure ...
(7.7000003 7.2000003 1.7 5.6 7.5 2.2 5.0 7.6 2.0 4.9 2.9 1.6 0.4 6.1 3.3 7.1 8.7 6.5 5.6 9.2)

4 个答案:

答案 0 :(得分:2)

在浮点数的上下文中,这是完全预期和适当的。每种其他语言都是一样的。

二进制浮点数(由IEEE定义)不能完全表示所有小数部分。例如,二进制中的小数部分0.20.0011001100110011....,因此您无法使用有限的位数精确表示它。因此,许多浮点数必然是四舍五入的。如果将它们相加,则会出现舍入误差。有时他们互相取消,有时不会。如果你将它们相乘(就像你那样),它们会相乘。

如果您想拥有精确的分数,Common Lisp可以让您使用有理数。例如,如果计算(/ 1 5),则得到1/5,这是这种有理数的打印表示,这是精确的(在内部,计算适用于分子和分母)。您可以使用以下确切数字进行计算:

CL-USER> (+ 1/5 2/3)
13/15

CL-USER> (+ 3/5 2/5)
1

为了将它们打印出作为小数,您可以使用格式控件~f,例如:

CL-USER> (format t "~,3f" 13/15)
0.867

答案 1 :(得分:1)

奇怪的行为是什么?

您是否担心,例如,0.1 * 99似乎是9.90001?这对浮点数来说是正常的。他们不精确。他们牺牲精确度来获得射程。你不能指望在没有放弃的情况下得到一些东西。

答案 2 :(得分:1)

如果您想要rational个号码,请不要使用浮点数...

(loop for i from 1 to 20 collect (/ (random 100) 10))

答案 3 :(得分:0)

(loop for i from 1 to 20 collect (read-from-string (format nil "~v$" 1 (/ (random 100) 10))))