Проверка равенства чисел с плавающей запятой в Python проверяется на соответствие машинным допускам эпсилон?

Меня немного смущает точность чисел с плавающей запятой в Python и проверки равенства.

например.,

15 + 1e-16 == 15

оценивается как истинное, поскольку 1e-16 <машинный эпсилон для fp64.

и

15 + 1e-15 == 15

оценивает ложь, потому что 1e-15 > машинный эпсилон для fp64.

Но когда я делаю sys.getsizeof(15 + 1e-16), я получаю 24 байта, то есть fp192, что, если бы это было правдой, означало бы, что 15 + 1e-16 == 15 будет оценивать ложь, поскольку машинный эпсилон для fp192 наверняка << 1e-16.

Я всегда думал, что == проверяет, находится ли левая часть тела в пределах +/- эпсилона машины соответствующего типа.

Чтобы еще больше усугубить мое замешательство, я проверил:

1e-323 == 0 # evaluates false
1e-324 == 0 # evaluates true
sys.getsizeof(1e-323) # gives 24 bytes

Я не понимаю ограничений в этом.

Во-первых, sys.getsizeof дает размер объекта в памяти, который может включать в себя некоторые накладные расходы; это не то же самое, что, скажем, sizeof в C. Таким образом, размер 24 не означает, что вы на самом деле имеете дело со 192-битной плавающей запятой повышенной точности. И затем, к вашему главному вопросу, большинство языков (включая Python) реализуют == как строгое равенство. Если вам нужен примерный тест на равенство, вы часто можете действовать самостоятельно. (Но см. peps.python.org/pep-0485 .)

Steve Summit 20.05.2024 20:10

Кроме того, «машинный эпсилон» — это абсолютная точность около 1,0. Для чисел около 16 эффективный эпсилон будет в 8 или 16 раз больше.

Steve Summit 20.05.2024 20:16

@SteveSummit «реализовать == как строгое равенство», ах, я понимаю, но строгое равенство — это просто проверка того, что побитовое равенство дает равенство, верно? Я действительно думал, что это эквивалентно проверке допусков на эпсилон?

roulette01 20.05.2024 20:25

То, что сравнивается побитово, — это значение двойной точности IEEE754 (все его 64 бита), и сравнение проводится для точного равенства. То, что вы набрали, вообще не сравнивается — на ранней стадии интерпретатор Python переводит символы 1e-324 в ближайшее значение двойной точности IEEE754, и именно это значение в конечном итоге сравнивается. И оказывается, что в случае 1 e - 3 2 4 ближайшее значение двойной точности IEEE754 равно 0,0.

Steve Summit 20.05.2024 23:12

«Строгое равенство — это просто проверка того, что побитовое равенство дает равенство, верно?» --> Нет. -0.0 == +0.0 верно, но имеет разные битовые комбинации. a == a обычно является ложным, когда a не является числом, но a и a имеют одинаковую битовую комбинацию.

chux - Reinstate Monica 28.05.2024 23:46
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
5
73
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Сравнение всех числовых типов (включая числа с плавающей запятой) в Python является точным. Точность оборудования здесь ни при чем.

getsizeof() возвращает размер объекта Python, который включает в себя такие вещи, как байты для указателя на объект типа объекта и счетчик ссылок. Фактические данные для числа с плавающей запятой занимают 8 байт практически на всех современных машинах, лишь небольшую часть.

Когда вы говорите «точный», вы имеете в виду точный в битовом представлении, а не в математическом смысле?

roulette01 20.05.2024 20:26

Оба. Сравнение видит только битовые представления. Это арифметические операции (+, -, *, ...), которые могут потерять информацию из-за округления. Сравнения принимают исходные данные за чистую монету и выполняют точное сравнение предполагаемых точных сравнений.

Tim Peters 20.05.2024 20:44

Понятно, а как насчет 1e-324 == 0? Очевидно, что это не математическая эквивалентность, а эквивалент в коде из-за ограничений аппаратной точности?

roulette01 20.05.2024 20:49

Сравнение равенства по-прежнему является точным - оно всегда точно ;-) Это литерал 1e-324 сам по себе, изолированно, который теряет информацию из-за округления. Оно слишком мало для представления вашим аппаратным обеспечением, поэтому округляется ровно до 0, ближайшего числа, которое может представлять ваше аппаратное обеспечение.

Tim Peters 20.05.2024 20:56

И если это не ясно, то происходит следующее: строка 1e-324, которую вы вводите в своей программе на Python, более или менее сразу преобразуется в 0,0, а затем 0,0 становится равным 0. То есть при анализе вашего кода 1e-324 преобразуется в 0, а позже, при вычислении выражения, оценщику выражения предлагается сравнить 0,0 и 0,0.

Steve Summit 20.05.2024 23:06

@SteveSummit Верно, я понимаю, что оно преобразуется в 0. Пробел в моем понимании заключается в том, что я не знал числового порога, при котором значение преобразуется в 0. Сколько себя помню, я всегда думал, что числовой порог равен машинный eps (~2.2e-16 для двойной точности IIRC), но теперь я вижу, что на самом деле не имею к этому никакого отношения

roulette01 21.05.2024 03:01

~2,2e-16 — это наименьшая степень 2, которая при добавлении к 1,0 не полностью теряется при ближайшем/четном округлении. Он равен math.ulp(1.0), весу степени 2 наименее значимого представимого бита 1,0. 1.0 + math.ulp(1.0) больше 1, но 1.0 + math.ulp(1.0) / 2 ровно 1,0.`

Tim Peters 21.05.2024 03:23

Итак, 2,2e-16 — это абсолютная точность в диапазоне (бинаде) от 1,0 до 2. От 2,0 до 4 — это вдвое больше. От 0,5 до 1 — это вдвое меньше. А вблизи минимального значения двойной точности (именно это нас здесь волнует) оно составляет 2⁻¹⁰²², или около 5e-324. Вот почему 1e-323 заметно отличался от 0, а 1e-324 — нет. (И, следовательно, эпсилон действительно имеет к этому отношение, если вы правильно на него смотрите, то есть масштабируете.)

Steve Summit 21.05.2024 05:27

Другие вопросы по теме