Предположим, что t
, a
, b
- все двойные (IEEE Std 754) переменные, и оба значения a
, b
НЕ NaN
(но могут быть Inf
),
После t = a - b
у меня обязательно есть a == b + t
?
Плавающая точка IEEE Std 754: пусть t: = a - b, гарантирует ли стандарт, что a == b + t?
Ответ 1
Абсолютно нет. Один очевидный случай - a=DBL_MAX
, b=-DBL_MAX
. Тогда t=INFINITY
, поэтому b+t
также INFINITY
.
Что может быть более удивительным, так это случаи, когда это происходит без переполнения. В основном, они все формы, где a-b
неточно. Например, если a
- DBL_EPSILON/4
, а b
- -1
, a-b
равно 1 (если используется режим округления по умолчанию), а a-b+b
- 0.
Причина, по которой я упоминаю этот второй пример, заключается в том, что это канонический способ принудительного округления до определенной точности в арифметике IEEE. Например, если у вас есть число в диапазоне [0,1] и хотите принудительно округлить его до 4 бит точности, вы должны добавить, а затем вычесть 0x1p49
.
Ответ 2
В процессе выполнения первой операции бит мог быть потерян с нижнего конца результата. Итак, один вопрос: будет ли вторая операция точно воспроизвести эти потери? Я не совсем так думал.
Но, конечно, первая операция могла переполняться до +/- бесконечности, делая второе сравнение неравным.
(И, конечно, в общем случае использование ==
для значений с плавающей запятой почти всегда является ошибкой.)
Ответ 3
При использовании поплавков ничего не гарантируется. Если экспонента отличается для обоих чисел, результат арифметической операции не может быть полностью представлен в поплавке.
Рассмотрим этот код:
float a = 0.003f;
float b = 10000000.0f;
float t = a - b;
float x = b + t;
Запустив Visual Studio 2010, вы получите t==-10000000.0f
и, следовательно, x==0
.
Вы не должны использовать равенство при сравнении поплавков. Вместо этого сравните абсолютное значение разницы между обоими значениями и значением epsilon, достаточно малым для ваших точных потребностей.
Он становится еще более странным, поскольку различные реализации с плавающей запятой могут возвращать разные результаты для одной и той же операции.