コンテンツにスキップ
Wikipedia

「利用者:Giant2007/sandbox」の版間の差分

削除された内容 追加された内容
1行目: 1行目:
{{Otheruses|数の表現|[[広瀬正]]のSF小説|マイナス・ゼロ}}<!--名作-->

'''-0'''(マイナスゼロ)、あるいは'''負のゼロ'''とは、数値のゼロにマイナスの符合をつけたものである。

通常の算術では、負のゼロは正のゼロである+0と同一であると見なされるが、両者を分けて考える方が望ましい場合や、分けて考えざるを得ない場合がある。

そのようなケースとして、以下のものがある
* [[極限]]操作に伴って生じるケース。例えば[[片側極限|右方極限]] ''x'' →+0と[[片側極限|左方極限]] ''x'' → -0 を分けて考えるケースや、1/∞、1/(-∞)をそれぞれ+0、-0と見なすケース
* 正負の概念を持つ[[コンピュータの数値表現|数値表現]]において、正負の概念を0にも適応する事で生じるケース。おもに[[コンピューター]]・[[プログラム]]で問題になる。
* [[数値計算]]において、誤差を丸める際、 「0 より小さいが -1 まで[[端数処理|丸める]]には絶対値が小さすぎる量」の意味で負のゼロを用いるケース
* [[統計力学]]における[[負温度]]

最初のものについては[[片側極限]]の項目、最後のものは[[負温度]]の項目を参照。
本項ではそれ以外の2つのケースについて取り扱う。


なお、負のゼロと同種の理由で、正のゼロである「+0」と符合のないゼロである「0」を区別しなければならない場合もあるが、本項ではこの問題については割愛し、 「+0」と「0」を同一視する。

==数値表現としての負のゼロ==
==数値表現としての負のゼロ==



2016年1月14日 (木) 05:35時点における版

数値表現としての負のゼロ

数値表現において符合の概念をゼロにも適応した結果として負のゼロが生じる場合がある。

例えば整数をN進法で表現する場合、ゼロ以外の数は、

  • +(数値)
  • -(数値)

のいずれかの形に一意に表現できる。 しかしゼロのみは

  • +0
  • -0

の二種類の表現が可能である為、負のゼロの問題が生じる。

この事が原因で、0のみ例外処理が必要になる場合がある。

例えば2つの数値

  • A=(符合1)(数値1)
  • B=(符合2)(数値2)

が等しいかどうかを判定するために以下のようなプログラムを書くとバグを作り込むこととなる:

  • if(符合1と符合2が等しく、数値1も数値2と等しい)
    • 「A=B」と出力
  • else
    • 「A≠B」と出力

このプログラムにA=+0、B=-0を代入すると、本来は「A=B」を出力しなければならないはずだが、両者の符合が異なることが原因で「A≠B」を出力してしまう。

このように負のゼロは、プログラムにおいてバグの原因になってしまうので、慎重に取り扱う必要がある。

この種の問題の根本的解決としては、そもそも負のゼロが生じない数値表現を選ぶ、という方法があるが、他の問題との兼ね合いによっては、必ずしもこれが最良な解決になるとは限らない。

コンピューターでは補数を利用して負数を表現する事が多いが、同じ補数でも基数の補数 を利用した場合には負のゼロが生じないのに対し、減基数の補数 を用いた場合には負のゼロが生じる。

IEEE 754における負のゼロ

この節に雑多な内容が羅列されています 事項を箇条書きで列挙しただけの節は、本文として組み入れるか、または整理・除去する必要があります。(2016年1月)

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

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

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

算術

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

  • 0 | x | = 0 {\displaystyle {\frac {-0}{\left|x\right|}}=-0,円\!} {\displaystyle {\frac {-0}{\left|x\right|}}=-0,円\!} ( x {\displaystyle x} {\displaystyle x} は0以外)
  • ( 0 ) ( 0 ) = + 0 {\displaystyle (-0)\cdot (-0)=+0,円\!} {\displaystyle (-0)\cdot (-0)=+0,円\!}
  • | x | ( 0 ) = 0 {\displaystyle \left|x\right|\cdot (-0)=-0,円\!} {\displaystyle \left|x\right|\cdot (-0)=-0,円\!}

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

  • x + ( ± 0 ) = x {\displaystyle x+(\pm 0)=x,円\!} {\displaystyle x+(\pm 0)=x,円\!}
  • ( 0 ) + ( 0 ) = ( 0 ) ( + 0 ) = 0 {\displaystyle (-0)+(-0)=(-0)-(+0)=-0,円\!} {\displaystyle (-0)+(-0)=(-0)-(+0)=-0,円\!}
  • ( + 0 ) + ( + 0 ) = ( + 0 ) ( 0 ) = + 0 {\displaystyle (+0)+(+0)=(+0)-(-0)=+0,円\!} {\displaystyle (+0)+(+0)=(+0)-(-0)=+0,円\!}
  • x x = x + ( x ) = + 0 {\displaystyle x-x=x+(-x)=+0,円\!} {\displaystyle x-x=x+(-x)=+0,円\!} (任意の有限の x {\displaystyle x} {\displaystyle x}について、負方向への丸めの場合は −0)

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

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

  • 0 = 0 {\displaystyle {\sqrt {-0}}=-0,円\!} {\displaystyle {\sqrt {-0}}=-0,円\!} [4]
  • 0 = + 0 {\displaystyle {\frac {-0}{-\infty }}=+0,円\!} {\displaystyle {\frac {-0}{-\infty }}=+0,円\!} (除算の符号規則に従う)
  • | x | 0 = {\displaystyle {\frac {\left|x\right|}{-0}}=-\infty ,円\!} {\displaystyle {\frac {\left|x\right|}{-0}}=-\infty ,円\!} ( x {\displaystyle x} {\displaystyle x}がゼロでない場合、除算の符号規則に従う)
  • ± 0 × ± = NaN {\displaystyle {\pm 0}\times {\pm \infty }={\mbox{NaN}},円\!} {\displaystyle {\pm 0}\times {\pm \infty }={\mbox{NaN}},円\!} (NaNまたは割り込み発生)
  • ± 0 ± 0 = NaN {\displaystyle {\frac {\pm 0}{\pm 0}}={\mbox{NaN}},円\!} {\displaystyle {\frac {\pm 0}{\pm 0}}={\mbox{NaN}},円\!}

複素数など

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

比較

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

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

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

DoublenegativeZero=newDouble(-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 (7 April 2009). "Decimal Arithmetic: Arithmetic operations – square-root". speleotrove.com (IBM Corporation). 2010年12月7日閲覧。
  5. ^ Class Double

参考文献

関連項目

AltStyle によって変換されたページ (->オリジナル) /