为什么 math.isclose() 无法检测到非常大的值之间的微小差异?

Why does math.isclose() fail to detect minor differences between very large values?

提问人:AFoeee 提问时间:10/27/2018 最后编辑:Paul RoubAFoeee 更新时间:9/21/2019 访问量:1504

问:

math.isclose()存在以确定两个值之间的差值是否在容差范围内。
据我了解,此容差的默认值为:

  • rel_tol = 1e-09
  • abs_tol = 0.0


如果我将两个值都设置为 ,那么它应该测试这两个值是否相同。0.0

这似乎适用于较小的值:

import math

math.isclose(1000, 1000, rel_tol=0.0, abs_tol=0.0)                       # True
math.isclose(1000, 1001, rel_tol=0.0, abs_tol=0.0)                       # False

但是它失败了,值非常大:

import math
import sys

math.isclose(sys.maxsize, sys.maxsize,      rel_tol=0.0, abs_tol=0.0)    # True
math.isclose(sys.maxsize, sys.maxsize-1,    rel_tol=0.0, abs_tol=0.0)    # True
math.isclose(sys.maxsize, sys.maxsize-100,  rel_tol=0.0, abs_tol=0.0)    # True
math.isclose(sys.maxsize, sys.maxsize-1000, rel_tol=0.0, abs_tol=0.0)    # False

看来还是有相对宽容的?


为什么会发生这种行为?

上面的代码是用 Python 3.5.2 运行的。


更新1:

使用非常大的浮点值时,似乎会发生类似的行为:

import math
import sys

m = sys.float_info.max                                                    # type 'float'

math.isclose(m, m)                                                        # True
math.isclose(m, m-1.0)                                                    # True
math.isclose(m, m-1e100)                                                  # True
math.isclose(m, m-1e300)                                                  # False

math.isclose(m, m,       rel_tol=0.0, abs_tol=0.0)                        # True
math.isclose(m, m-1.0,   rel_tol=0.0, abs_tol=0.0)                        # True
math.isclose(m, m-1e100, rel_tol=0.0, abs_tol=0.0)                        # True
math.isclose(m, m-1e300, rel_tol=0.0, abs_tol=0.0)                        # False

另一方面,比较运算符在这里也不起作用。

import math
import sys

m = sys.float_info.max                                                    # type 'float'

m == m                                                                    # True
m < m                                                                     # False
m > m                                                                     # False

m == m-1.0                                                                # True
m < m-1.0                                                                 # False
m > m-1.0                                                                 # False

m == m-1e100                                                              # True
m < m-1e100                                                               # False
m > m-1e100                                                               # False

m == m-1e300                                                              # False
m > m-1e300                                                               # True
m < m-1e300                                                               # False

更新2:

这里给出了“更新 1”的答案。

python-3.x 比较 精度 相等

评论


答:

6赞 Tim Peters 10/27/2018 #1

sys.maxsize是一个整数,但适用于浮点值。在 64 位盒子上,精度比浮点数可以表示的要多,因此对于所有足够小的正整数。math.isclose()sys.maxsizefloat(sys.maxsize - N) == float(sys.maxsize)N

>>> from sys import maxsize as m
>>> m
9223372036854775807
>>> float(m)
9.223372036854776e+18
>>> float(m - 1)  # identical
9.223372036854776e+18
>>> float(m - 100) # identical 
9.223372036854776e+18
>>> float(m - 1000)  # finally subtracting enough to make a tiny difference
9.223372036854775e+18

短期课程:当您想比较整数是否相等时,首先转换为浮点数根本没有意义。

评论

0赞 AFoeee 10/27/2018
我很困惑。 指定 1.7976931348623157e+308 作为最大值。如果它的射程小于?sys.float_info.maxsys.maxsize
1赞 Tim Peters 10/27/2018
sys.float_info.max是浮点数可以具有的最大值。Python 整数的最大值没有固有限制。 只是用作索引的 Python 整数可以具有的最大值。这是三个不同的概念。sys.maxsize
1赞 Tim Peters 10/27/2018
顺便说一句,如果您需要了解浮点的基础知识,只需搜索网络即可。例如,en.wikipedia.org/wiki/Floating-point_arithmetic 在浮点数中,精度位数与最大动态范围(指数可以有多大)之间没有特定的联系。在您的机器上,Python 浮点数几乎可以肯定具有(确切地)53 位精度,但动态范围跨越大约 600(十进制)数量级(标准 IEEE-754“双精度”格式的所有特征)。
0赞 AFoeee 10/28/2018
如果我理解正确,则发生上述行为是因为我使用整数值而不是浮点值。使用非常大的浮点值时,似乎也会发生类似的事情。(我在问题中添加了一个示例。我想这也是因为超出了精度限制。有没有可以安全操作的范围?