Плавающая точка IEEE Std 754: пусть t: = a - b, гарантирует ли стандарт, что a == b + t?

Предположим, что t, a, b - все двойные (IEEE Std 754) переменные, и оба значения a, b НЕ NaN (но могут быть Inf), После 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, достаточно малым для ваших точных потребностей.

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