Причина остатка в умножении python - PullRequest
1 голос
/ 15 января 2020

Почему в некоторых умножениях с плавающей точкой в ​​python эти странные остатки?

например,

>>> 50*1.1
55.00000000000001

, но

>>> 30*1.1
33.0

Причина должна быть где-то в двоичное представление чисел с плавающей запятой, но в чем разница, в частности, в обоих примерах?

1 Ответ

1 голос
/ 15 января 2020

(В этом ответе предполагается, что ваша реализация Python использует двоичный код IEEE-754, который является общим.)

Когда 1.1 преобразуется в число с плавающей запятой, результат в точности равен 1.100000000000000088817841970012523233890533447265625, поскольку это ближайшее представимое значение. (Это число 4953959590107546 • 2 −52 - целое число, умноженное не более чем на 53 бита, умноженное на степень два.)

При умножении на 50 точный математический результат равен 55.00000000000000444089209850062616169452667236324512667236324512667236329122667236324512667236329122667236324512667236329122667236324512667236329122667236324512667236329122667236324512667236329122667236324512667236329122667236324500 , Это не может быть точно представлено в двоичном виде64. Для того, чтобы вписать его в формат binary64, оно округляется до ближайшего представимому значения, которое 55,00000000000000710542735760100185871124267578125 (который 7740561859543041 • 2-47).

1009 * Когда она умножается на 30, точный результат 33,00000000000000266453525910037569701671600341796875. он также не может быть представлен точно в двоичном виде64. Он округляется до ближайшего представимого значения, которое равно 33. (Следующее более высокое представимое значение равно 33.00000000000000710542735760100185871124267578125, и мы можем видеть, что ... 026 ближе к ... 000, чем к ... 071.)

Это объясняет, что внутреннее результаты есть. Затем возникает проблема того, как ваша реализация Python форматирует вывод. Я не верю, что реализация Python является строгой в этом отношении, но, вероятно, используется один из двух методов:

  • По сути, число преобразуется в определенное количество десятичных цифр, и затем удаляются незначительные нули. Преобразование 55.00000000000000710542735760100185871124267578125 в число с 16 цифрами после десятичной точки приводит к получению 55.00000000000001, который не имеет конечных нулей для удаления. Преобразование 33 в число с 16 цифрами после десятичной точки приводит к получению 33.00000000000000, который имеет 15 конечных нулей для удаления. (Предположительно, ваша реализация Python всегда оставляет хотя бы один завершающий ноль после десятичной запятой, чтобы четко отличить guish, что это число с плавающей запятой, а не целое число.)
  • Достаточно десятичного числа цифры используются для однозначного отличия guish числа от смежных представимых значений. Этот метод требуется в Java и JavaScript, но пока не распространен в других языках программирования. В случае 55.00000000000000710542735760100185871124267578125, печать «55.00000000000001» отличает его от соседних значений 55 (которые будут отформатированы как «55,0») и 55.0000000000000142108547152020037174224853515625 (что было бы «55.000000000000014»).
...