負のゼロが重要なのはなぜですか?


64

正と負のゼロの異なる表現を気にする理由について私は混乱しています。

複素数を含むプログラミングでは、負のゼロ表現を持つことが非常に重要であるという主張を漠然と思い出しました。複素数を含むコードを書く機会がなかったので、なぜそうなるのか少し困惑しています。

この概念に関するウィキペディアの記事は特に有用ではありません。私が正しく理解すれば、符号付きゼロについて漠然とした主張をするだけで、浮動小数点での特定の数学的操作が簡単になります。この回答には、動作が異なる2つの関数がリストされています。これらの関数の使用方法に精通している場合は、例から何かを推測できます。(ただし、複雑な平方根の特定の例は完全に間違っいるように見えます、2つの数字は数学的に同等なので、誤解がない限り)。しかし、それがないとあなたが直面するようなトラブルの明確な説明を見つけることができません。私が見つけたより数学的なリソースは、数学的な観点からこの2つを区別することができないという状態を見つけることができました。

では、なぜ負のゼロはコンピューティングで価値があるのでしょうか?私は何かを逃していると確信しています。


6
負のゼロは、IEEE浮動小数点数のアンダーフローを示すことができますが、それを超えると、その使用は議論の余地があり、あいまいになります。推測すると、IEEE浮動小数点では負のゼロが表現されていると思います。 さらに興味深いライドについては、浮動小数点シグナルNaNに関する情報を参照してください。
ロバートハーヴェイ

1
特定の例が「1 / 0.0」/「1 / -0.0」の場合、0は1 / xの分岐カットであり、制限は下から上に近づくかどうかによって異なります。
バティーン

@Vatineいいえ、特定の例はsqrt(-1+0i) = iand sqrt(-1-0i) = -iです。一部のプログラミング言語の適切な構文でドレスアップされていますが、私は信じています。より明確になるように編集します。
jpmc26

3
プログラマースタックオーバーフローコンピューターサイエンス数学エンジニアリングを検索しました。私が見つけることができた唯一の質問は、負のゼロ浮動小数点値の使用ですか?。これは、これが現れたのは2回目だけではありません!

特に指摘した平方根の例を考えると、答えに複素数がまったく含まれていないことに本当に驚いています。
jpmc26

回答:


69

FPU算術では、0は必ずしも正確に0を意味する必要はありませんが、与えられたデータ型を使用して表現するには小さすぎる値も覚えておく必要があります。

a = -1 / 1000000000000000000.0

aは小さすぎてfloat(32ビット)で正しく表現できないため、-0に「丸め」られます。

さて、計算が続くとしましょう:

b = 1 / a

aは浮動小数点数であるため、-1000000000000000000.0の正解とはほど遠い-infinityになります。

-0がない場合、bを計算しましょう(aは+0に丸められます):

b = 1 / +0
b = +infinity

丸めのために結果は再び間違っていますが、今では「より間違っています」-数値だけでなく、より重要なことは異なる符号のためです(計算の結果は+∞、正しい結果は-1000000000000000000.0)。

あなたはまだ両方が間違っているので、それは本当に重要ではないと言うことができます。重要なことは、計算の最も重要な結果が符号である多くの数値アプリケーションがあることです。たとえば、機械学習アルゴリズムを使用して交差点で左折するか右折するかを決定する場合、正の値=> turnと解釈できます左、負の値=>右に曲がって、値の実際の「大きさ」は単に「信頼係数」です。


虚数/複素数の計算でアンダーフローの兆候が特に重要かどうかについてのアイデアはありますか?
jpmc26

@qbd:それらの数値アプリケーションが何であるか知っていますか?通常の操作でトリガーおよび使用するプログラムにはバグがある+infと思います-inf
ビョルンリンドクヴィスト

@BjörnLindqvist具体的なダウンロード可能なアプリケーションが必要な場合-私は知りません。私はそれが必ずしもバグだとは思わない-フロート/ダブルの代わりに、BigDecimalのようなものを無限の精度で使用することができます。しかし、プログラムがfloat / doubleを使用した場合とまったく同じ結果を提供するが、パフォーマンスがはるかに悪い場合、それは価値がありますか?
qbd

あなたは、私はそれを信じることができる「の計算の最も重要な結果は符号がある数値計算アプリケーション」を書いたが、私は-0で、値があることに依存している任意のよく書かれたアプリケーションがあると信じてすることはできません+infとは-inf。プログラムが浮動小数点アンダーフローを引き起こす場合、それがバグであり、その後に何が起こるかはそれほど面白くありません。-0が役立つ実用的な例はまだありません。
ビョルンリンドクヴィスト

1
@BjörnLindqvistx265の大部分はアセンブリで行われますが、パフォーマンスの名前でほとんど知られていない(CPUアーキテクチャに依存する)あいまいな詳細に依存しています。違いますか?広く実装されている30年前の標準(これは今後も続く)に依存して、パフォーマンスという名のシンプルでよく理解された機能を突然使用することは、それほど悪くはないようです。
qbd

8

まず、-0をどのように作成しますか?2つの方法があります。(1)数学的な結果が負の浮動小数点演算を実行しますが、ゼロに非常に近いため、非ゼロではなくゼロに丸められます。その計算は-0になります。(b)ゼロを含む特定の操作:正のゼロに負の数を乗算するか、正のゼロを負の数で除算するか、正のゼロを否定します。

負のゼロを使用すると、乗算と除算が少し簡略化され、x * yまたはx / yの符号は常にxの符号、排他的符号、またはyの符号になります。負のゼロがなければ、-0を+0に置き換えるための追加のチェックが必要になります。

役に立つ非常にまれな状況がいくつかあります。アンダーフローがある場合でも、乗算または除算の結果が数学的にゼロより大きいか小さいかを確認できます(結果が数学的なゼロでないことがわかっている場合)。違いを生むコードを書いたことは今まで覚えていません。

コンパイラの最適化は-0が嫌いです。たとえば、xが-0.0の場合、結果はxにはならないため、x + 0.0をxに置き換えることはできません。x <0またはxが-0.0の場合、結果は-0.0になるはずなので、x * 0.0を0.0に置き換えることはできません。


7
IEEE-754には、「正確」、正の無限小、負の無限小、および符号なし(後者は区別できない値の違い)の4つのゼロが含まれていたと思います。これを行うと、多くの浮動小数点公理が機能します-x + 0.0 equiv x-0.0 equiv x、xy equiv x +(-1.0)* y、1.0 / x equiv -1.0 /(-1.0 * x)[xが正のゼロの場合、両方ともpos-infになります。負のゼロの場合、両方とも負のINF。正確または符号なしの場合は、両方NaN]。
supercat

私は渡すことによって、負のゼロを得ることができた-55fmod()。私のユースケースにとっては非常に迷惑です。
アーロンフランケ

6

IEEE 754に準拠するC#Double

    double a = 3.0;
    double b = 0.0;
    double c = -0.0;

    Console.WriteLine(a / b);
    Console.WriteLine(a / c);

プリント:

Infinity
-Infinity

実際に少し説明するために...

Double d = -0.0; 

これは、d = The Limit of x as x approaches 0-またはにより 近いものを意味しますThe Limit of x as x approaches 0 from the negatives


フィリップのコメントに対処するには...

基本的に負のゼロはアンダーフローを意味します。

負のゼロの実用的な使用法はほとんどありません...

たとえば、次のコード(再びC#):

double a = -0.0;
double b = 0.0;

Console.WriteLine(a.Equals(b));
Console.WriteLine(a==b);
Console.WriteLine(Math.Sign(a));

この結果が得られます:

True
True
0

非公式に説明すると、IEEE 754浮動小数点が持つことができるすべての特別な値(正の無限大、負の無限大、NAN、-0.0)は、実際の意味では意味がありません。物理的な値、または「実世界」の計算で意味のある値を表すことはできません。基本的には次のとおりです。

  • 正の無限大は、浮動小数点が表すことができる正の端でのオーバーフローを意味します
  • 負の無限大は、浮動小数点が表すことができる正の端でのオーバーフローを意味します
  • 負のゼロはアンダーフローを意味し、オペランドの符号は反対でした
  • 正のゼロアンダーフローを意味する場合あり、オペランドの符号は同じでした
  • NANは、計算がのようsqrt(-7)に無制限に未定義であるか、0/0またはのような制限が ないことを意味しますPositiveInfinity/PositiveInfinity

7
はい、しかしなぜこれが重要なのですか?違いが重要な実用的で現実的な例を提供できますか?
フィリップ

5

これが複素数の計算にどのように関係するかについての質問は、実際に浮動小数点に+0と-0の両方が存在する理由の中心になります。複素数解析をまったく研究すると、出力が「リーマン面」として知られる「ポライトフィクション」を採用しない限り、複素数から複素数への連続関数は通常、「単一値」として扱うことができないことがすぐにわかります。たとえば、複素対数は各入力に無限に多くの出力を割り当てます。連続出力を形成するために「接続」すると、すべての実部品が原点の周りに「無限コルクねじ」面を形成することになります。「正-虚側から下向き」に実軸を横切る連続曲線と、「極の周りを包み」、実軸を横切る別の曲線

次に、複雑な浮動小数点を使用して計算する数値プログラムに適用します。特定の計算の後に実行されるアクションは、プログラムが現在「オン」になっている「シート」によって大きく異なる場合があり、最後に計算された結果の符号は、おそらく「シート」を示します。ここで、結果がゼロであったと仮定しますか?ここで、「ゼロ」は実際には「小さすぎて正しく表現できない」ことを意味します。ただし、結果がゼロのときに計算で-符号を保持する(つまり、どの「シート」を記憶する)ように調整できる場合、コードはこの状況でも符号をチェックして適切なアクションを実行できます。


1

理由はいつもより簡単です

もちろん、本当に見栄えが良く便利なハックがたくさんあります(丸める、-0.0または+0.0先頭にマイナス/プラス記号のある符号付きintの表現があると仮定する(U2バイナリコードによって解決されることを知っています)通常は整数ですが、それほど複雑ではないdoubleの表現を想定しています):

0 111 = 7
^ sign

負の数がある場合はどうなりますか?

1 111 = -7

さて、それは簡単です。それでは、0を表します。

0 000 = 0

それも大丈夫です。しかし、どう1 000ですか?禁止された番号である必要がありますか?より良い

したがって、ゼロには2つのタイプがあると仮定しましょう。

0 000 = +0
1 000 = -0

さて、それは計算を簡素化し、幸いなことに追加の機能を切り上げます。そのため、+0and -0は単なるバイナリ表現の問題に由来しています。


6
私がこれを正しく読んでいるなら、あなたは基本的に、標準を定義または実装している人々がそれを禁止する問題に行きたくないと言っているだけです。この推論は、2の補数が完全に異なる数に「負のゼロ」表現を使用し、負のゼロの表現を持たないという事実に当てはまるとは思わない。リンクしたウィキペディアの記事を参照してください。
jpmc26

1
@ jpmc26それは実際に何らかの真実があると思います。それを禁止しないということは、実装に特別なケースを持たせる必要がないことを意味します。そのままでは、すべての数値に符号ビットがあり、符号ビットを切り替えることで無効にできます。NaNでさえ署名されており、実装はNaNを生成するときに適切な署名を選択できます(ただし、必須ではありません)。負のゼロが存在しない場合、0になったすべての計算は、符号ビットなどを修正するために追加の作業を行う必要があります。
hobbs

4
@ jpmc26(つまり、2つの数値のすべての乗算では、結果の符号は被乗数の符号のxorであり、大きさは2つの大きさの積です。実際には、これは-1 * 0 =- 0.しかし、符号ビットが反転したゼロが特別なゼロ以外の値である場合、0を生成できるすべての製品は、誤ってその特別な値を生成しないことを確認し、確認する必要があります。)
hobbs
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.