Странные проблемы с суммированием int и float - PullRequest
0 голосов
/ 09 мая 2020

Кто-нибудь, пожалуйста, объясните мне это?

Я писал def (программу) для преобразования текста в числа и хотел убедиться, что это были только целые числа, представление было целым, а если плавающее, то плавающим. Если смесь, по умолчанию используется плавающий режим. Тестирование на суммировании дало интересные вещи. По мере того, как я тестировал больше, он становился еще более странным.

Если бы это всегда было одно из двух, возможно, я мог бы обратиться, но, насколько я понимаю, это непоследовательно. Я слышал, что это вызывает беспокойство, и существуют библиотеки, которые обращаются к желаемому состоянию (десятичные типы), но почему это происходит? Меня это беспокоит. Должна ли я быть?

Примеры ниже варьируются от «да, это имеет смысл» до «а?» на "как в ???". И это происходит в пределах числа в непосредственной близости. Я имею в виду, когда это 5,8 против 6,8, и вы получаете эту дельту в результате. WT ???

TIA для любых идей. Я уверен, что это где-то старые новости :)

Все запускаются из командной строки, хотя из кода то же самое. Использование Python 3.8.2 Некоторые примеры:

-2 + 4,5 => 2,5 "да, это имеет смысл"

-6,8 + 8 => 1.2000000000000002 "да?"

-2 + 3,8 => 1,7999999999999998 «как в ???»

-5,8 + 8 => 2,2

-7,8 + 8 => 0.20000000000000018

-8,8 + 8 => -0,8000000000000007

-4,8 + 8 => 3,2

-4-3,8 + 8 => 0.20000000000000018

-4 + 3,8 => -0.20000000000000018

-3 + 3,8 => 0,7999999999999998

-1 + 3,8 => 2,8

1 Ответ

0 голосов
/ 09 мая 2020

Когда -6,8 преобразуется в 64-битный двоичный формат с плавающей запятой IEEE-754, он не может быть представлен, поэтому вместо него создается ближайшее представимое значение. Это значение равно −6. CCCCCCCCCCCCC 16 . Когда добавляется 8, получается 1,3333333333334 16 . В десятичном формате это 1.20000000000000017763568394002504646778106689453125. Некоторое программное обеспечение отображает это как 1.2000000000000002.

Обратите внимание, что при преобразовании 1,2 в этот формат результат будет 1,3333333333333 16 , а не 1,3333333333334 16 . Это отличается от -6,8 + 8, потому что при -6,8 округление должно происходить в позиции 2 -50 бит, потому что представление -6,8 требует, чтобы биты начинались с 2 2 , и в мантиссе 53 бита (часть представления с плавающей запятой, которая представляет собой «дробную» часть числа). В версии 1.2 первый бит находится в позиции 2 0 , а округление происходит в позиции 2 -52 . Таким образом, преобразование 1,2 в формат с плавающей запятой дает результат ближе к 1,2, чем −6,8 + 8.

При отображении чисел с плавающей запятой некоторые программы для форматирования по умолчанию выдают столько же десятичных цифр поскольку необходимы, чтобы однозначно отличить guish число с плавающей запятой от его соседних представимых значений. Когда 1,2 преобразуется в 1,3333333333333 16 , а затем форматируется как десятичное, создается «1,2», потому что это однозначно отличает 1,3333333333333 16 . Но когда отформатировано 1,3333333333334 16 , необходимо создать «1.2000000000000002», чтобы отличить guish от 1,3333333333333 16 .

Другие примеры аналогичный. В таких случаях, как -5,8 + 8, происходит округление, чтобы получить тот же результат, что и при прямом преобразовании 2,2, поэтому на выходе получается «2,2». В других случаях округление работает немного иначе, и вы получаете другой результат.

...