Предположим, что t
, a
, b
все двойные (IEEE Std 754) переменные, и оба значения a
, b
НЕ NaN
(но может быть Inf
). После t = a - b
, у меня обязательно есть a == b + t
?Плавающая точка IEEE Std 754: пусть t: = a - b, гарантирует ли стандарт, что == b + t?
ответ
Абсолютно нет. Один очевидный случай - 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
.
Второй пример замечательный, поскольку он не несет Inf или NaN. Большое спасибо. – updogliu
Возможно, вы захотите уточнить константу '0x1p49', последний раз, когда я посмотрел шестнадцатеричные цифры, пробег от 0 до F;) – MSalters
@MSalters:« 0x1p49 »- это шестнадцатеричная плавающая запятая, как определено в стандарте C. Формат «0x»
В процессе выполнения первой операции бит мог быть потерян с нижнего конца результата. Итак, один вопрос: будет ли вторая операция точно воспроизвести эти потери? Я не совсем так думал.
Но, конечно, первая операция могла бы переполняться до +/- бесконечности, делая второй сравнивать неравномерно.
(И, конечно же, в общем случае, используя ==
для значений с плавающей точкой почти всегда является ошибкой.)
Только с помощью аргумента подсчета вторая операция не может вернуть то, что было потеряно. Если это возможно, вы будете хранить больше бит информации в 't', чем количество бит в' t' ... –
@R - Да. Интуитивно известно, что это не сработает, из-за того, что вы говорите, но найти примеры лучше «доказательство», чем обращение к эзотерическому правилу, независимо от того, насколько он действителен. –
Вы не гарантировано ничего при использовании поплавков. Если экспонента отличается для обоих чисел, результат арифметической операции может быть не полностью представлен в поплавке.
Рассмотрим этот код:
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, достаточно малым для ваших точных потребностей.
Он становится еще более странным, поскольку различные реализации с плавающей точкой могут возвращать разные результаты для одной и той же операции.
Мне никогда не нравился совет «сравните абсолютную ценность разницы». Можно получить ограничения на ошибки ([Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой] (http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) является хорошим начало), и нужно подумать о том, чего пытаешься добиться при сравнении, прежде чем вслепую переключиться на какую-то произвольную границу. –
Есть много вещей, которые гарантируются при использовании поплавков IEEE-754. Это не один из них. –
Есть много гарантий при использовании поплавков IEEE, и бывают случаи, когда сравнение для равенства не только разумно, но и существенно. Математика с плавающей запятой определенно сложна, но она не случайна и не злонамерена. Вот пример из моего блога, когда критическое значение имеет равенство с плавающей точкой: https://randomascii.wordpress.com/2014/01/27/theres-only-four-billion-floatsso-test-them-all/ –
- 1. #define func (t, a, b) {\t t temp; \t temp = a; \t a = b; б = темп;}
- 2. Плавающая точка IEEE 754, что является наибольшим числом <1?
- 3. T-SQL COUNT 'A', 'B' и 'A or B'
- 4. Для {A = a; B = B; }, будет ли «A = a» строго выполняться до «B = b»?
- 5. Расчет (A - B (D^-1) B^T)^- 1 с CUDA
- 6. Почему плавающая точка IEEE-754 не обменивается между платформами?
- 7. Почему "echo [a-z]" печатает "b t"?
- 8. SELECT a FROM T + Выбрать b из T или SELECT a, b FROM T? H2 База данных
- 9. Функция в качестве параметра шаблона: if (T получает 2 параметра) T (a, b); иначе T (a);
- 10. Что делает эта функция с a, b = b, a + b?
- 11. Как разбить массив A * A std :: на куски B * B?
- 12. Что такое IEEE-754?
- 13. проверяет, находится ли нецелое число в диапазоне [a, b) - или [a, b], (a, b), (a, b]
- 14. Почему стандарт IEEE 754 использует смещение 127?
- 15. Плавающая точка IEEE-754: разделите сначала или размножайте сначала для лучшей точности?
- 16. C++: "T a = b" - копировать конструктор или оператор присваивания?
- 17. T-Tree или B-Tree
- 18. Swift: преобразование массива [A, B, B, B, A, B, B, B] в массив хэш [[A: [B, B, B], [A: [B, B, B ]]]
- 19. В чем разница между ['[a, a, a]', '[b, b, b]'] и [[a, a, a], [b, b, b]] в python?
- 20. Ошибки возникают при вызове печати (список <T> a, T b) с другим классом T
- 21. Почему (a | b) эквивалентно a - (a & b) + b?
- 22. Что означает b = a && b в C?
- 23. Доказывая `T b`, когда` b` уже согласованы на
- 24. Может ли оптимизатор предположить, что плавающая точка не NaN?
- 25. Действительно ли a = = b действительно эквивалентно a = a + b?
- 26. Преобразование из типа `T Ā` в` T b` без шаблонного
- 27. Докажите, что A == B, B == C, A! = C
- 28. Как убедить coq, что (A/\ B)/\ C == A/\ B/\ C?
- 29. Означает ли <'a, 'b: 'a>, что время жизни 'b должно пережить время жизни' a?
- 30. Как реализованы Perl -T и -B?
Я считаю, что результат нижнего потока был бы неопределенным, и так будет переполнение во втором выражении, так что нет. Если кто-то сможет это подтвердить, было бы хорошо. – chris
Ах, я думаю, этот тип подтверждает, что переполнение не определено для с плавающей запятой: 'As с любым другим арифметическим переполнением, если результат не установлен в указанном пространстве, поведение не определено.' – chris
В реализации C в соответствии с IEEE 754, нет UB для любой арифметики с плавающей точкой. Все результаты строго определены. –