浮動小数点演算に関するIEEE 754-2008規格とISO / IEC 10967言語非依存演算(LIA)規格、パート1は、これがなぜそうなのかを回答しています。
IEEE 754§6.3符号ビット
入力または結果がNaNの場合、この規格はNaNの符号を解釈しません。ただし、ビット文字列の操作(copy、negate、abs、copySign)はNaNの結果の符号ビットを指定することに注意してください。NaNオペランドの符号ビットに基づいている場合もあります。論理述語totalOrderも、NaNオペランドの符号ビットの影響を受けます。他のすべての演算については、入力NaNが1つしかない場合や、無効な演算からNaNが生成された場合でも、この規格はNaN結果の符号ビットを指定しません。
入力も結果もNaNでない場合、積または商の符号は、オペランドの符号の排他的ORです。合計の符号、または合計x +(-y)と見なされる差x-yの符号は、最大で1つの加数の符号とは異なります。変換結果の符号、量子化演算、roundTo-Integral演算、およびroundToIntegralExact(5.3.1を参照)は、最初または唯一のオペランドの符号です。これらの規則は、オペランドまたは結果がゼロまたは無限の場合にも適用されます。
反対の符号を持つ2つのオペランドの合計(または同様の符号を持つ2つのオペランドの差)が正確にゼロの場合、その合計(または差)の符号は、roundTowardNegativeを除くすべての丸め方向属性で+0になります。その属性の下では、正確なゼロ和(または差)の符号は-0になります。ただし、x + x = x −(−x)は、xがゼロであってもxと同じ符号を保持します。
追加の場合
デフォルトの丸めモードでは (ラウンドには、最も近い、ネクタイツーであっても)、私たちはそれが見x+0.0
生成x
する場合を除き、x
されて-0.0
:その場合は、我々は合計ゼロで反対の符号を持つ2つのオペランドの合計を持っている、と§6.3段落この追加によって生成される3つのルール+0.0
。
以来+0.0
ないビット単位元と同じ-0.0
、それは-0.0
、入力として発生することがあり、正当な値であり、コンパイラは、潜在的に負のゼロを変換するコードに配置する義務があります+0.0
。
要約:デフォルトの丸めモードの下でx+0.0
、x
- でない場合
-0.0
、それx
自体が許容可能な出力値です。
- で
-0.0
ある場合、出力値はでなければなりません +0.0
。これはとビットごとに同一ではありません-0.0
。
乗算の場合
デフォルトの丸めモードでは、このような問題は発生しませんx*1.0
。の場合x
:
減算の場合
デフォルトの丸めモードでは、減算x-0.0
はと同等であるため、何もしませんx + (-0.0)
。もしx
IS
- isの
NaN
場合、§6.3p1と§6.2.3 は、加算と乗算の場合とほとんど同じ方法で適用されます。
- isの
+/- infinity
場合、結果は+/- infinity
同じ符号になります。
x-0.0 == x
常に(準)通常の数です。
- で
-0.0
ある場合、§6.3p2によって、「[...]合計の符号、または合計x +(-y)と見なされる差x-yの符号は、最大で1つの加数の符号と異なります。」これは、米軍が割り当てること-0.0
の結果として(-0.0) + (-0.0)
ので、-0.0
からの符号が異なるなし加数の、一方の+0.0
符号が異なるから2加数のこの句に違反して、。
- で
+0.0
、これはまた、ケースに減少し(+0.0) + (-0.0)
て上で考慮さ添加の場合 §6.3p3によって与えることを支配され、+0.0
。
すべての場合において、入力値は出力として正当であるためx-0.0
、ノーオペレーションとx == x-0.0
トートロジーを考慮することは許容されます。
価値を変える最適化
IEEE 754-2008規格には、興味深い引用があります。
IEEE 754§10.4文字通りの意味と値を変える最適化
[...]
特に、次の値を変更する変換では、ソースコードの文字通りの意味が保持されます。
- xがゼロではなく、シグナリングNaNでなく、結果がxと同じ指数である場合に、アイデンティティプロパティ0 + xを適用します。
- xがシグナルNaNではなく、結果がxと同じ指数である場合に、アイデンティティプロパティ1×xを適用します。
- クワイエットNaNのペイロードまたは符号ビットを変更します。
- [...]
すべてのNaNとすべての無限大は同じ指数を共有し、有限のx+0.0
とx*1.0
について正しく丸められた結果はとx
正確に同じ大きさなのでx
、それらの指数は同じです。
sNaNs
シグナルNaNは浮動小数点トラップ値です。これらは、浮動小数点オペランドとして使用すると無効演算例外(SIGFPE)が発生する特別なNaN値です。例外をトリガーするループが最適化された場合、ソフトウェアは同じように動作しなくなります。
ただし、user2357112 がコメントで指摘しているように、C11標準ではシグナルNaN(sNaN
)の動作が明示的に未定義のままになっているため、コンパイラーはそれらが発生しないと想定できるため、発生する例外も発生しません。C ++ 11標準では、シグナルNaNの動作の説明が省略されているため、未定義のままになっています。
丸めモード
別の丸めモードでは、許容される最適化が変更される場合があります。たとえば、Round-to-Negative-Infinityモードでは、最適化x+0.0 -> x
は許可x-0.0 -> x
されますが、禁止されます。
GCCがデフォルトの丸めモードおよび動作を想定しないようにするために、実験的なフラグ-frounding-math
をGCCに渡すことができます。
結論
ClangとGCCは、現在でも-O3
IEEE-754に準拠しています。これは、IEEE-754標準の上記の規則を守る必要があることを意味します。x+0.0
あるビット同一ではないにx
すべてのためにx
これらのルールの下で、しかし、x*1.0
そうなるように選択することができる:とき私たち、すなわち、
x
NaNの場合のペイロードを変更せずに渡すという推奨に従います。
- NaNの結果の符号ビットは、によって変更されません
* 1.0
。
- がNaNで
x
はない場合、商/積の間に符号ビットをXORする順序に従います。
IEEE-754-unsafe最適化を有効にするには(x+0.0) -> x
、フラグ-ffast-math
をClangまたはGCCに渡す必要があります。