3

这在常见的 lisp(clisp 和 sbcl)和方案(guile)中都有。虽然这些都是真的:

(= 1/2 0.5)
(= 1/4 0.25)

事实证明这是错误的:

(= 1/5 0.2)

我检查了超规范,它说“=”应该检查数学等价性,尽管参数的类型。到底他妈发生了什么?

4

4 回答 4

21

问题是 0.2 真的等于 1/5。浮点数不能正确表示 0.2,因此文字 0.2 实际上四舍五入到最接近的可表示浮点数(0.200000001 或类似的东西)。发生此舍入后,计算机无法知道您的数字最初是 0.2 而不是附近的另一个不可表示的数字(例如 0.20000000002)。

至于 1/2 和 1/4 之所以起作用,是因为浮点是基数为 2 的编码,可以准确地表示 2 的幂。

于 2012-08-03T01:03:53.917 回答
10

请阅读每个计算机科学家应该了解的关于浮点数的知识

于 2012-08-03T09:52:25.153 回答
1

这实际上取决于什么被强制到什么。如果您考虑一下,那么理性更精确,因此强制比较理性而不是浮动是有意义的,但是,如果您有意识地将数字作为浮动进行比较,您可以通过执行以下操作来强制它:

(declaim (inline float=))
(defun float= (a b)
  (= (coerce a 'float) (coerce b 'float)))
(float= 0.2 1/5) ; T

实际上......还有更多,因为浮点数为您提供了诸如非数字、正无穷大和负无穷大之类的东西。例如,对于 64 位浮点数,无穷大是 10e200 iirc,因此,没有什么可以阻止您创建一个大于无穷大(或小于负无穷大!)的理性,所以,也许,如果你想要超级精确,你也需要考虑这些情况。同样,与非数字的比较必须始终给您零……

于 2012-08-03T09:13:54.057 回答
1

但是,在方案中你有确切的数字,所以你可能会问(注意 #e 前缀,这意味着后面的数字要被准确对待):

> (= 1/5 #e0.2)
#t
于 2012-08-03T12:11:55.617 回答