Страницы

Поиск по вопросам

понедельник, 25 ноября 2019 г.

Ляп в Питоне: x + 1.0 < x


При смешивании типов возможно неочевидное поведение:

>>> x = (1 << 53) + 1
>>> x + 1.0 < x
True


Казалось бы, что x + 1.0 не меньше просто x, поэтому ожидаемый результат сравнения False, но возвращается True. Почему?
    


Ответы

Ответ 1



Кратко: 9007199254740992.0 < 9007199254740993 При сложении, числа к общему типу приводятся в Питоне. x (int) конвертируется в float так как 1.0 это float. x непредставим точно в виде float, поэтому выбирается ближайшее (меньшее здесь) представимое число: x -> float(x-1). Поэтому сумма получается неточной: x+1.0 -> float(x-1)+1.0 -> (x) -> float(x-1) Сравнение float < int происходит точно. Значение x (int) математически больше x+1.0 (float). Целые числа в Питоне имеют бесконечную точность (могут быть сколь угодно большими) Но вещественные числа, такие как создаваемые 1.0 константой в исходном коде, представлены типом float— числами с плавающей точкой. x слагаемое во float здесь превращается: otherwise, if either argument is a floating point number, the other is converted to floating point; ещё до вычисления суммы: the numbers are converted to a common type and then added together >>> x 9007199254740993 >>> float(x) == float(x-1) == 9007199254740992.0 True >>> x+1.0 == float(x) + 1 == float(x-1) + 1 == float(x) == float(x-1) True На IEEE 754 платформах, где Python float соответствует числам с двойной точностью: >>> sys.float_info.radix 2 >>> sys.float_info.mant_dig 53 >>> float(1<<53).hex() # точно представлено '0x1.0000000000000p+53' >>> float((1<<53) + 1).hex() # непредставимо точно, округляется '0x1.0000000000000p+53' >>> (float((1<<53) + 1) + 1.0).hex() # двойное округление '0x1.0000000000000p+53' Вывод показывает, что float(x) и x + 1.0 представлены как одно и то же число: float(x-1). Подробнее см. вопрос Отображение числа 9223372036854775807. x является int, поэтому величина (1<<53)+1 точно представлена (9007199254740993). Сравнение математически точно происходит без приведения типов: The objects do not need to have the same type. ... Within the limits of the types involved, they compare mathematically (algorithmically) correct without loss of precision. >>> 9007199254740992.0 < 9007199254740993 True Вот так x + 1.0 может быть меньше x в Питоне.

Комментариев нет:

Отправить комментарий