IEEE 754における負のゼロ
現在多くのコンピュータやプログラミング言語が採用している浮動小数点数の標準であるIEEE 754には通常の 0(以下 +0 と書く)の他に負のゼロである −0がある。本項では、IEEE 754における負のゼロと通常の 0との取り扱いについて述べる。
IEEE 754 の仕様策定の際、符号付きのゼロを採用するといくつかのクリティカルな問題で数値的な正確さ(accuracy)の達成が(精度(precision)ではない)容易になると主張され[1]、特に複素数の初等関数の計算が挙げられた[2]。
正のゼロと負のゼロは算術比較演算では等しいと判定されるが、一部演算では異なる結果を生じる(「ビットパターンが異なるため」ではない。#複素数などの節を参照のこと)。
表現
[編集]IEEE 754 の二進浮動小数点数では、ゼロは指数部と仮数部がゼロで表され、負のゼロの場合はさらに符号ビットが 1 となる。計算結果が負の極めて小さい値で算術アンダーフローとなった場合、負のゼロが結果として得られる。また、−1.0 * 0.0 の計算結果も負のゼロとなる。そのプログラミング言語のリテラルが対応していれば、単に −0.0
と記述しても負のゼロになる。
IEEE 754 の十進浮動小数点数では、負のゼロの指数部は任意の正規の値で、仮数部は全てゼロであり、符号ビットが 1 で表される。
属性と操作
[編集]IEEE 754 では、正のゼロと負のゼロを各種演算で使用したときの振る舞いを規定している。計算結果は丸めモードの設定に影響される。
算術
[編集]標準において、その計算は正と負の無限大を含む拡大実数を対象としており[3]、1/−0 = −∞ および 1/+0 = +∞ となるような2つのゼロが存在する。すなわちこの場合に限っては0をある種の無限小のように扱っている。標準では一般に任意の非ゼロ数のゼロ除算は、正負どちらかの無限大になり、ゼロのゼロ除算は NaN になる。
それ以外の乗除算は通常の符号の組み合わせと同じように扱われる。
- ( は0以外)
加減算は値が相殺される場合特別に扱われる。
- (任意の有限のについて、負方向への丸めの場合は −0)
負のゼロが存在するため、浮動小数点数の変数 x
、y
、z
を使った式 z = -(x - y)
や z = (-x) - (-y)
を z = y - x
と最適化することはできない。
他に次のような特別規則がある。
複素数など
[編集]一般に複素数などの極座標表示においては、その偏角に を加減しても複素数としては同じ値を示す、という性質がある。通常は代表値として、偏角を とすると に制限するなどするが、マイナスゼロがある場合、の偏角を とするのに対し の偏角を とする、といったように使い分ける用例がある。複素数を使わない場合でも、たとえば atan2(-0.0, -1.0)
が になる実装がある。
比較
[編集]標準では、C言語やJavaの ==
演算子のような通常の(数値としての)比較では、負のゼロと正のゼロは等しいと判定されることとしている。
特に負のゼロのみの判定が可能な API としては、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言語では、可搬(portable)な技法ではないが(標準ではそのような操作の結果は「未定義」である。strict aliasing rule)、var が IEEE 754の単精度である場合、
*(uint32_t *)&var == 0x80000000UL
で、負のゼロかどうか比較できる。
共用体を利用すれば、このようなアクセスが標準では「処理系定義」であるので、可搬性(portability)が少しはマシである。
脚注
[編集]- ^ 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.
- ^ さらに NaN がある。
- ^ Cowlishaw, Mike (7 April 2009). “Decimal Arithmetic: Arithmetic operations – square-root”. speleotrove.com (IBM Corporation). 2010年12月7日閲覧。
- ^ Class Double
参考文献
[編集]- “Floating point types”. MSDN C# Language Specification. 2005年10月15日閲覧。
- “Division operator”. MSDN C# Language Specification. 2005年10月15日閲覧。
- Thomas Wang (2000年3月). Java Floating-Point Number Intricacies. 2000年9月 .
- Kittel, Charles; and Herbert Kroemer (1980年). Thermal Physics. W. H. Freeman & Company. ISBN 0716710889
- Mike Colishaw (28 July 2008). “Decimal Arithmetic Specification, version 1.68”. 2008年8月14日閲覧。 — 負のゼロを含む十進浮動小数点数の仕様。
- Michael Ingrassia. “Fortran 95 SIGN Change”. Sun Developer Network. 2005年10月15日閲覧。 — FORTRAN の
SIGN
関数が、負のゼロを扱えるよう Fortran 95 で変更された。 - “JScript data types”. MSDN JScript. 2005年10月16日閲覧。 — JScript の浮動小数点型は定義として負のゼロを持つ。
- “A look at the floating-point support of the Java virtual machine”. Javaworld. 2005年10月16日閲覧。 — Java仮想マシンにおける負のゼロの表現
- Bruce Dawson. “Comparing floating point numbers”. 2008年3月6日閲覧。 — 浮動小数点数を比較する際に負のゼロをどう扱うか
- John Walker. “Minus Zero”. UNIVAC Memories. 2005年10月17日閲覧。 — UNIVAC® 1100 ファミリにおける1の補数表現