IEEE 754における負のゼロ

現在多くのコンピュータやプログラミング言語が採用している浮動小数点数の標準であるIEEE 754には通常の 0（以下 +0 と書く)の他に負のゼロである −0がある。本項では、IEEE 754における負のゼロと通常の 0との取り扱いについて述べる。

IEEE 754 の仕様策定の際、符号付きのゼロを採用するといくつかのクリティカルな問題で数値的な正確さ（accuracy）の達成が（精度（precision）ではない）容易になると主張されWilliam Kahan, "Branch Cuts for Complex Elementary Functions, or Much Ado About Nothing's Sign Bit", in The State of the Art in Numerical Analysis (eds. Iserles and Powell), Clarendon Press, Oxford, 1987.、特に複素数の初等関数の計算が挙げられたWilliam Kahan, Derivatives in the Complex z-plane, p10.。

正のゼロと負のゼロは算術比較演算では等しいと判定されるが、一部演算では異なる結果を生じる（「ビットパターンが異なるため」ではない。#複素数などの節を参照のこと）。

 表現 
IEEE 754 の二進浮動小数点数では、ゼロは指数部と仮数部がゼロで表され、負のゼロの場合はさらに符号ビットが 1 となる。計算結果が負の極めて小さい値で算術アンダーフローとなった場合、負のゼロが結果として得られる。また、−1.0 * 0.0 の計算結果も負のゼロとなる。そのプログラミング言語のリテラルが対応していれば、単に −0.0 と記述しても負のゼロになる。

IEEE 754 の十進浮動小数点数では、負のゼロの指数部は任意の正規の値で、仮数部は全てゼロであり、符号ビットが 1 で表される。

 属性と操作 
IEEE 754 では、正のゼロと負のゼロを各種演算で使用したときの振る舞いを規定している。計算結果は丸めモードの設定に影響される。

 算術 
標準において、その計算は正と負の無限大を含む拡大実数を対象としておりさらに NaN がある。、1/−0 = −∞ および 1/+0 = +∞ となるような2つのゼロが存在する。すなわちこの場合に限っては0をある種の無限小のように扱っている。標準では一般に任意の非ゼロ数のゼロ除算は、正負どちらかの無限大になり、ゼロのゼロ除算は NaN になる。

それ以外の乗除算は通常の符号の組み合わせと同じように扱われる。
  （ は0以外）



加減算は値が相殺される場合特別に扱われる。



  （任意の有限のについて、負方向への丸めの場合は −0）

負のゼロが存在するため、浮動小数点数の変数 x、y、z を使った式 z = -(x - y) や z = (-x) - (-y) を z = y - x と最適化することはできない。

他に次のような特別規則がある。

   （除算の符号規則に従う）
   （がゼロでない場合、除算の符号規則に従う）
  （NaNまたは割り込み発生）


 複素数など 
一般に複素数などの極座標表示においては、その偏角に  を加減しても複素数としては同じ値を示す、という性質がある。通常は代表値として、偏角を  とすると  に制限するなどするが、マイナスゼロがある場合、の偏角を  とするのに対し の偏角を  とする、といったように使い分ける用例がある。複素数を使わない場合でも、たとえば atan2(-0.0, -1.0) が  になる実装がある。

 比較 
標準では、C言語やJavaの == 演算子のような通常の（数値としての）比較では、負のゼロと正のゼロは等しいと判定されることとしている。

特に負のゼロのみの判定が可能な API としては、IEEE 754 の中では、copysign() 関数で、ゼロの符号をゼロでない何らかの数にコピーすることで正負を明確化することができる。C言語ではC99で標準となった。Java では、Double クラスでの equals メソッドは負のゼロと正のゼロを区別するClass Double。例えば、

Double negativeZero = new Double(-0.0);
negativeZero.equals(-0.0); // Result: true
negativeZero.equals( 0.0); // Result: false

以下は、後で紹介するものほどトリック的な方法となる。まず、(int)var のように普通に型キャストすると、負のゼロのない2の補数表現の整数では単なるゼロになってしまうので比較できない。

任意の非ゼロの値を除算して、正のゼロと負のゼロを区別できる。
 1.0 / +0.0 = +∞
 1.0 / −0.0 = −∞

により、整数型としてアクセスし、ビットパターンとして比較する。C言語では、可搬（portable）な技法ではないが（標準ではそのような操作の結果は「未定義」である。strict aliasing rule）、var が IEEE 754の単精度である場合、

*(uint32_t *)&var == 0x80000000UL

で、負のゼロかどうか比較できる。

共用体を利用すれば、このようなアクセスが標準では「処理系定義」であるので、可搬性（portability）が少しはマシである。

 脚注 

 参考文献 




  — 負のゼロを含む十進浮動小数点数の仕様。
  — FORTRAN の SIGN関数が、負のゼロを扱えるよう Fortran 95 で変更された。
  — JScript の浮動小数点型は定義として負のゼロを持つ。
  — Java仮想マシンにおける負のゼロの表現
  — 浮動小数点数を比較する際に負のゼロをどう扱うか
  — UNIVAC® 1100 ファミリにおける1の補数表現

 関連項目 
 整数
 0
 正の数と負の数
 コンピュータの数値表現
符号付数値表現
補数
 位取り記数法

0-
0-