使用Common Lisp中的分数进行等式检查

时间:2015-10-01 14:03:37

标签: common-lisp precision floating-accuracy fractions

所以我知道Lisp会做出很棒的分数。但是为什么这个等式检查会返回NIL:

LinkedHashMap

...如果它首先转换为* (= 0.2 1/5) NIL ,则返回True:

float

我已在* (= 0.2 (float 1/5)) T SBCL中尝试过。

实施是否不完整或是否存在此行为背后的特殊原因或逻辑?

2 个答案:

答案 0 :(得分:6)

Common Lisp中的比率

请注意,分数(它本身不是Common Lisp中的数字类型)在Lisp中转换为 reasonals rationalratiointeger(以及其他)是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.51/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类型结合了不相交的子类型ratiointeger。因此(rational 1.0)可以是整数,而不是比率。

答案 1 :(得分:3)

关于=的{​​{3}}说:

  

如果所有数字的值相同,则=的值为true;否则就是假的。

虽然real上的specification说:

  

rationalfloat类型是real类型的不相交子类型。

换句话说,您可以比较它们,因为它们都是数字,但它们是不同的,因为由于子类型是不相交的,它们是不同的值。

你可以做的是将它们转换为数字的相同“子集”,浮点数,然后比较将返回true。

这种行为的原因是float数字通常具有近似表示(参见@coredump和链接的注释),而有理数具有精确表示,因此比较不是很明智可以“看起来”外部相同但在内部(二进制)表示中不同的值。