Правильно ли, что любая арифметическая операция над любыми плавающими числами однозначно определяется стандартом IEEE с плавающей запятой? Если да, просто для любопытства, что такое (+0)+(-0)
? И есть ли способ проверить такие вещи на практике, на С++ или другом часто используемом языке программирования?
Что такое (+0) + (- 0) стандартом с плавающей запятой IEEE?
Ответ 1
Правила арифметики IEEE 754 для подписанных нулей указывают, что +0.0 + -0.0
зависит от режима округления. В режиме округления по умолчанию это будет +0.0
. При округлении до -∞ это будет -0.0
.
Вы можете проверить это на С++ так:
#include <iostream>
int main() {
std::cout << "+0.0 + +0.0 == " << +0.0 + +0.0 << std::endl;
std::cout << "+0.0 + -0.0 == " << +0.0 + -0.0 << std::endl;
std::cout << "-0.0 + +0.0 == " << -0.0 + +0.0 << std::endl;
std::cout << "-0.0 + -0.0 == " << -0.0 + -0.0 << std::endl;
return 0;
}
+0.0 + +0.0 == 0
+0.0 + -0.0 == 0
-0.0 + +0.0 == 0
-0.0 + -0.0 == -0
Ответ 2
Мой ответ посвящен IEEE 754: 2008, который является текущей версией стандарта.
В стандарте IEEE 754: 2008:
В разделе 4.3 рассматривается округление значений при выполнении арифметических операций, чтобы соответствовать битам в мантиссе.
4.3 Атрибуты округления
Округление принимает число, считающееся бесконечно точным, и, при необходимости, изменяет его, чтобы оно соответствовало формату адресатов, когда сигнализировало неточное исключение, недополнение или переполнение, если это необходимо (см. 7). За исключением случаев, когда указано иное, каждая операция должна выполняться так, как если бы она сначала производила промежуточный результат, правильный для бесконечной точности и с неограниченным диапазоном, а затем округлял этот результат в соответствии с одним из атрибутов в этом разделе.
Атрибут rounding-direction влияет на все вычислительные операции, которые могут быть неточными. Неточные числовые значения с плавающей запятой всегда имеют тот же знак, что и результат без окружения.
Атрибут rounding-direction влияет на знаки точных нулевых сумм (см. 6.3), а также влияет на пороговые значения, за которыми сигнализируются переполнение и недополнение.
В разделе 6.3 предписывается значение знакового бита при выполнении арифметики со специальными значениями (NaN, бесконечности, +0, -0).
6.3 Знаковый бит
Когда сумма двух операндов с противоположными знаками (или разностью двух операндов с одинаковыми знаками) равна нулю, знак этой суммы (или разности) должен быть +0 во всех атрибутах округления, за исключением
roundTowardNegative
; под этим атрибутом знак точной нулевой суммы (или разности) должен быть -0.Однако x + x = x - (-x) сохраняет тот же знак, что и x, даже когда x равно нулю.
(акцент мой)
Иными словами, (+0) + (-0) = +0, за исключением случаев, когда режим округления roundTowardNegative
, в в этом случае это (+0) + (-0) = -0.
В контексте С#:
В соответствии с §7.7.4 Спецификация языка С# (основное внимание):
- Добавление с плавающей запятой:
float operator +(float x, float y);
double operator +(double x, double y);
Сумма вычисляется в соответствии с правилами арифметики IEEE 754. В следующей таблице перечислены результаты всех возможных комбинаций ненулевых конечных значений, нулей, бесконечностей и NaN. В таблице x и y являются ненулевыми конечными значениями, а z - результат x + y. Если x и y имеют одинаковую величину, но противоположные знаки, z - положительный нуль. Если x + y слишком велико для представления в целевом типе, z - бесконечность с тем же знаком, что и x + y.
+ • x +0 -0 +∞ -∞ NaN
•••••••••••••••••••••••••••••••••••••••••••••
y • z y y +∞ -∞ NaN
+0 • x +0 +0 +∞ -∞ NaN
-0 • x +0 -0 +∞ -∞ NaN
+∞ • +∞ +∞ +∞ +∞ NaN NaN
-∞ • -∞ -∞ -∞ NaN -∞ NaN
NaN • NaN NaN NaN NaN NaN NaN
(+ 0) + (-0) в С#:
Другими словами, на основе спецификации добавление двух нулей приводит только к отрицательному нулю, если оба отрицательные ноль. Поэтому ответ на исходный вопрос
Что такое (+0) + (- 0) по стандарту IEEE с плавающей запятой?
равно +0.
Режимы округления в С#:
Если кто-то заинтересован в изменении режима округления в С#, в Есть ли эквивалент С# функции С++ fesetround()
?, Hans Passant утверждает:
Никогда не перебирайте управляющее слово FPU в С#. Это наихудшая возможная глобальная переменная, которую вы можете себе представить. Со стандартным несчастьем, которое вызывает глобальные перемены, ваши изменения не могут продолжаться и будут произвольно исчезать. Внутренний код обработки исключений в CLR сбрасывает его при обработке исключения.
Ответ 3
Предположите стандартный режим округления (который вы используете, если не знаете, что такое режим округления и как его изменить).
Если точный результат отличен от нуля, но настолько мал, что округляется до нуля, результат равен +0, если точный результат больше 0 и -0, если точный результат меньше 0. Эта ситуация только происходит для умножения и деления, а не для сложения и вычитания.
Существует несколько случаев, когда точный результат равен нулю. В этом случае результат равен -0 в следующих случаях: Добавление (-0) + (-0). Вычитание (-0) - (+0). Умножение, когда один фактор равен нулю, а другой фактор имеет противоположный знак (включая (+0) * (-0). Деление нуля на ненулевое число, включая бесконечность противоположного знака. Во всех остальных случаях результат равен +0.
Несчастный побочный эффект этого правила состоит в том, что x + 0.0 не всегда идентичен x (не тогда, когда x есть -0). С другой стороны, x - 0.0 всегда совпадает с x. Кроме того, x * 0.0 может быть +0 или -0, в зависимости от x. Это предотвращает некоторые оптимизации компиляторов, которые точно поддерживают IEE754 или затрудняют их работу.
Ответ 4
Ответ, по стандарту IEEE с плавающей запятой, равен +0.