Common lisp 公共Lisp中分数的相等性检查

Common lisp 公共Lisp中分数的相等性检查,common-lisp,precision,floating-accuracy,fractions,Common Lisp,Precision,Floating Accuracy,Fractions,所以我知道Lisp做分数,这很好。但是为什么这个相等检查返回NIL: * (= 0.2 1/5) NIL …如果先将其转换为float,则返回True: * (= 0.2 (float 1/5)) T 我试过SBCL和CLISP 实现是否不完整,或者这种行为背后是否有特殊原因或逻辑 about=上写着: 如果所有数字的值相同,则=的值为真;否则,这是错误的 而onreal上显示: 类型rational和float是类型real的不相交子类型 换句话说,您可以比较它们,

所以我知道Lisp做分数,这很好。但是为什么这个相等检查返回NIL:

* (= 0.2 1/5)          

NIL
…如果先将其转换为
float
,则返回True:

* (= 0.2 (float 1/5))

T
我试过
SBCL
CLISP

实现是否不完整,或者这种行为背后是否有特殊原因或逻辑

about
=
上写着:

如果所有数字的值相同,则
=
的值为真;否则,这是错误的

而on
real
上显示:

类型
rational
float
是类型
real
的不相交子类型

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

您可以将它们转换为相同的数字“子集”,float,然后比较将返回true


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

通用Lisp中的比率

请注意,分数(在公共Lisp中它本身不是数字类型)在Lisp中转换为有理数
rational
ratio
integer
(以及其他)是公共Lisp中的实际数字类型。如果您输入一个分数,它将标准化为有理数(整数或比率数)

数值比较

比较浮动和比率时,将浮动值转换为有理值,然后进行精确比较。请参阅:

比率未转换为浮动,但浮动转换为有理数。

出现问题的原因是某些浮动未转换为您预期的比率。根本的问题是浮点数不一定有精确的表示。给出天真的预期结果时,不需要将非精确数转换为精确有理数

不幸的是,
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
但是:


注意,类型
rational
组合了不相交的子类型
ratio
integer
。因此
(rational 1.0)
可以是一个整数,而不是一个比率。

浮点数的不精确性?另请参见,
(=0.51/2)
返回
T
。0.5在基2和基10端接:
CL-USER 14 > (= 0.2 (float 1/5))
T
CL-USER 15 > (= (rational 0.2) 1/5)
NIL