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

AFo*_*eee 4 python precision compare equality python-3.x

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
Run Code Online (Sandbox Code Playgroud)

但它失败了很大的值:

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
Run Code Online (Sandbox Code Playgroud)

似乎还有相对的宽容?


为什么会出现这种情况?

上面的代码是用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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

更新2:

这里给出了 '更新1'的答案.

Tim*_*ers 6

sys.maxsize是一个整数,但math.isclose()适用于浮点值.在64位的盒子上,sys.maxsize有比浮点数更多的精度位,所以float(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
Run Code Online (Sandbox Code Playgroud)

短期课程:当你想比较整数是否相等时,首先转换为float是没有意义的.