Почему math.isclose () не может обнаружить незначительные различия между очень большими значениями? - PullRequest
0 голосов
/ 27 октября 2018

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' был дан здесь .

1 Ответ

0 голосов
/ 27 октября 2018

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

Краткий курс: когда вы хотитесравнивать целые числа на равенство, сначала преобразование в число с плавающей точкой просто не имеет смысла.

...