Почему в арифметике с плавающей точкой 0.9999999999999999! = 1, но 0.9999999999999999 + 1 == 2 - PullRequest
0 голосов
/ 04 июля 2018

Я знаю, что это должна быть еще одна проблема точности с плавающей запятой: пусть x будет 0.9999999999999999. Тогда x + 1 == 2 в арифметике с плавающей точкой, но x! = 1. Что происходит? Вот что я попробовал на своей консоли ipython.

In [55]: x = 0.9999999999999999

In [56]: x==1
Out[56]: False

In [57]: x+1==2
Out[57]: True

[Редактировать] Существующие вопросы о неработающем вычислении с плавающей запятой в основном касаются ошибки представления FP, которая, по-видимому, не является здесь главной причиной.

Ответы [ 2 ]

0 голосов
/ 04 июля 2018

Используемый вами формат с плавающей запятой имеет значение 53 бита. Это означает, что он может представлять числа как 53-разрядное целое число, умноженное или разделенное на степень два.

Когда 0.9999999999999999 преобразуется в этот формат, ближайшим представимым значением является (2 53 -1) / 2 53 , что в точности равно 0,999999999999999988897769753748434595763683319091796875. Обратите внимание, что числитель использует ровно 53 бита.

Когда вы добавляете 1, математический результат будет (2 54 -1) / 2 53 . Числитель будет иметь 54 бита. Это не может быть представлено в формате с плавающей точкой, поэтому оно должно быть округлено, чтобы соответствовать. Два ближайших представимых значения:

  • (2 54 -2) / 2 53 = (2 53 -1) / 2 52 и
  • (2 54 −0) / 2 53 = 2.

Они оба одинаково далеки от точного математического результата. Правило разрыва связей заключается в использовании значения с нулем в младшем бите его значения. (Несмотря на то, что здесь я представил значение и целое число как целое, это дробная часть в формате с плавающей запятой, поэтому числителю 1 соответствует двоичное число 1.000000… 000 2 . )

Таким образом, когда 1 добавляется к 0.9999999999999999, вычисленный результат должен быть округлен до 2.

0 голосов
/ 04 июля 2018

В интервале от 0.5 до 1.0 у вас есть еще один бит для дробной части по сравнению с количеством битов в дробной части в интервале от 1.0 до 2.0. Так что это ожидается.

Вы можете иметь другой пример с:

0.9999999999 + 1234567890.0

, где в первом добавлении десять цифр 9.

Тип с плавающей точкой двойной точности (то есть 64 бита) (двоичный) имеет точность приблизительно шестнадцати десятичных цифр. Таким образом, число может быть запомнено только по его «первой» (т. Е. Наиболее значимой) примерно шестнадцати цифрам.

...