所以我知道Lisp会做出很棒的分数。但是为什么这个等式检查会返回NIL:
LinkedHashMap
...如果它首先转换为* (= 0.2 1/5)
NIL
,则返回True:
float
我已在* (= 0.2 (float 1/5))
T
和SBCL
中尝试过。
实施是否不完整或是否存在此行为背后的特殊原因或逻辑?
答案 0 :(得分:6)
Common Lisp中的比率
请注意,分数(它本身不是Common Lisp中的数字类型)在Lisp中转换为 reasonals 。 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, Rule of Float and Rational Contagion。
该比率未转换为浮动,但浮动转换为合理。
出现问题是因为某些浮点数未转换为您期望的比率。根本问题是浮点数不一定是精确表示。将非精确数转换为精确理数不是必要的,只能给出天真的预期结果。
不幸的是,将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)
可以是整数,而不是比率。
答案 1 :(得分:3)
关于=
的{{3}}说:
如果所有数字的值相同,则
=
的值为true;否则就是假的。
虽然real
上的specification说:
rational
和float
类型是real
类型的不相交子类型。
换句话说,您可以比较它们,因为它们都是数字,但它们是不同的,因为由于子类型是不相交的,它们是不同的值。
你可以做的是将它们转换为数字的相同“子集”,浮点数,然后比较将返回true。
这种行为的原因是float
数字通常具有近似表示(参见@coredump和链接的注释),而有理数具有精确表示,因此比较不是很明智可以“看起来”外部相同但在内部(二进制)表示中不同的值。