コンテンツにスキップ

利用者:Giant2007/sandbox

  • IEEE 754 > Giant2007/sandbox

現在多くのコンピュータやプログラミング言語がサポートしている浮動小数点数の標準であるIEEE 754には通常の 0(以下 +0 と書くの他負のゼロである -0がある。

本項では、IEEE 754における負のゼロと通常の 0との取り扱いについて述べる。

IEEE 754 の仕様策定の際、符号付きのゼロを採用するといくつかのクリティカルな問題で数値的な正確さ(accuracy)の達成が(精度(precision)ではない)容易になると主張され[1]、特に複素数の初等関数の計算が挙げられた[2]

一方で符号付きのゼロという概念は、-0 も +0 も同じ 0 だという多くの数学の領域での前提に反している為、一部の計算において -0 の存在を忘れてプログラムを組むと、思わぬバグの原因となることがある(その例は負のゼロの項目を参照)。

正のゼロと負のゼロは算術比較演算では等しいと判定されるが、一部演算では異なる結果を生じる[3]

表現法[編集]

IEEE 754 の binary32 での負のゼロ

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

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

属性と操作[編集]

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

算術[編集]

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

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

  • は0以外)

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

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

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

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

  • [4]
  • (除算の符号規則に従う)
  • がゼロでない場合、除算の符号規則に従う)
  • NaNまたは割り込み発生)

複素数など[編集]

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

比較[編集]

IEEE 754 規格は、C言語Java== 演算子のような通常の(数値としての)比較では、負のゼロと正のゼロは等しいと判定されることとしている。

IEEE 754 では copysign() 関数で、ゼロの符号をゼロでない何らかの数にコピーすることで正負を明確化することができる。C言語ではC99で標準となった。

Java では、Double クラスでの equals メソッドは負のゼロと正のゼロを区別する[5]。例えば、

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言語では、移植性のある技法ではないが(標準ではそのような操作の結果は「未定義」である。strict aliasing rule)、varIEEE 754の単精度である場合、

*(uint32_t *)&var == 0x80000000UL

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

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

脚注[編集]

  1. ^ 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.
  2. ^ William Kahan, Derivatives in the Complex z-plane, p10.
  3. ^ 「ビットパターンが異なるため」ではない。#複素数などの節を参照のこと。
  4. ^ Cowlishaw, Mike (2009年4月7日). “Decimal Arithmetic: Arithmetic operations – square-root”. speleotrove.com (IBM Corporation). 2010年12月7日閲覧。
  5. ^ Class Double

参考文献[編集]

関連項目[編集]