我发现Lisp可以处理分数,这很棒。但是为什么下面的等式检查会返回NIL:
* (= 0.2 1/5)
NIL
如果将它先转换为 float
,则返回值为 True:
* (= 0.2 (float 1/5))
T
我已经在
SBCL
和 CLISP
中尝试过。
这种行为是因为实现不完整,还是有特殊的原因或逻辑呢?我发现Lisp可以处理分数,这很棒。但是为什么下面的等式检查会返回NIL:
* (= 0.2 1/5)
NIL
如果将它先转换为 float
,则返回值为 True:
* (= 0.2 (float 1/5))
T
SBCL
和 CLISP
中尝试过。
这种行为是因为实现不完整,还是有特殊的原因或逻辑呢?在Common Lisp中的比例
请注意,分数(本身不是Common Lisp中的数字类型)会在Lisp中转换为有理数。 rational
,ratio
和integer
(以及其他类型)都是Common Lisp中的实际数字类型。如果您输入一个分数,则它将被规范化为有理数(整数或比率数)。
CL-USER 16 > 3/9
1/3
CL-USER 17 > 9/9
1
CL-USER 18 > 6/9
2/3
数字比较
当浮点数和比率进行比较时,浮点数值会被转换为有理数,然后进行精确比较。请参见:CLHS,浮点数和有理数的传染规则。
比率不会转换为浮点数,但浮点数会转换为有理数。
问题出现在一些浮点数未被转换为预期的比率上。根本问题在于浮点数并没有必然的精确表示。将非精确数字转换为精确比率,不一定会得到期望的结果。
不幸的是,将0.2
转换为有理数不一定是1/5
,而可能是这个数:
CL-USER 7 > (rational 0.2)
13421773/67108864
0.5
等同于1/2
。CL-USER 8 > (rational 0.5)
1/2
CL-USER 9 > (= 1/2 (rational 0.5))
T
CL-USER 10 > (= 1/5 (rational 0.2))
NIL
CL-USER 14 > (= 0.2 (float 1/5))
T
CL-USER 15 > (= (rational 0.2) 1/5)
NIL
rational
将不相交的子类型ratio
和integer
组合在一起。因此,(rational 1.0)
可能是一个整数,而不是比率。
(= 0.5 1/2)
返回T
。0.5 在二进制和十进制中都是有限小数:https://dev59.com/WXNA5IYBdhLWcg3wHp6B#1096929 - coredump