web-dev-qa-db-ja.com

異なる値タイプ間のゼロ除算動作の不一致

次のコードとコメントを検討してください:

Console.WriteLine(1 / 0); // will not compile, error: Division by constant zero

int i = 0;
Console.WriteLine(1 / i); // compiles, runs, throws: DivideByZeroException

double d = 0;
Console.WriteLine(1 / d); // compiles, runs, results in: Infinity   

コンパイラがゼロ除算定数と実行時にDivideByZeroExceptionをアクティブにチェックしていることは理解できますが、次のようになります。

ゼロ除算でdoubleを使用すると、例外をスローするのではなく、Infinityが返されるのはなぜですか?これは仕様によるものですか、それともバグですか?

キックのためだけに、私はVB.NETでもこれを行い、「より一貫性のある」結果を得ました。

dim d as double = 0.0
Console.WriteLine(1 / d) ' compiles, runs, results in: Infinity

dim i as Integer = 0
Console.WriteLine(1 / i) '  compiles, runs, results in: Infinity

Console.WriteLine(1 / 0) ' compiles, runs, results in: Infinity

編集:

Kekekelaのフィードバックに基づいて、私は以下を実行しました。

Console.WriteLine(1 / .0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001);

このテストはアイデアを裏付けているようで、0.0のリテラルダブルは実際には非常に非常に小さい分数であり、無限大になります...

41
Paul Sasik

簡単に言うと、doubleタイプは無限大の値を定義しますが、intタイプは定義しません。したがって、doubleの場合、計算の結果は、定義されているため、特定の型で実際に表現できる値になります。 intの場合、無限大の値がないため、正確な結果を返す方法がありません。したがって、例外です。

VB.NETの動作は少し異なります。整数除算は、/演算子を使用して自動的に浮動小数点値になります。これは、開発者が式1 / 2などを記述して0.5に評価することを可能にするためです。 C#と一貫性のある動作を確認したい場合は、次のことを試してください。

Console.WriteLine(1 \ 0)

上記の整数除算演算子(\ではなく/)の使用に注意してください。私はあなたが例外(またはコンパイルエラー-どちらかわからない)を受け取ると信じています。

同様に、これを試してください:

Dim x As Object = 1 / 0
Console.WriteLine(x.GetType())

上記のコードはSystem.Doubleを出力します。

不正確さのポイントについては、別の見方があります。 double型に正確にゼロの値がないわけではありません(あります)。むしろ、doubleタイプは、そもそも数学的に正確な結果を提供することを意図したものではありません。 (特定の値は正確に表現できます。ただし、calculationsは正確性を保証しません。)結局のところ、mathematicalexpression 1 / 0が定義されていません(最後にチェックしました)。しかし、xがゼロに近づくと、1 / xは無限大に近づきます。したがって、この観点から、ほとんどの分数n / mexactlyを表現できない場合、x / 0のケースを近似値として扱うことは理にかなっていますそして、それにapproaches-の値を与えます。ここでも、少なくとも無限大が定義されています。

35
Dan Tao

Doubleは浮動小数点数であり、正確な値ではないため、コンパイラーの観点から実際に除算しているのは、ゼロに近いものですが、正確にゼロではありません。

7
heisenberg

「数値」浮動小数点はそのようなものではないからです。浮動小数点演算:

  • 連想的ではありません
  • 分配的ではありません
  • 乗法逆数がない可能性があります

(いくつかの例は http://www.cs.uiuc.edu/class/fa07/cs498mjg/notes/floating-point.pdf を参照)

浮動小数点は特定の問題を解決するための構造であり、本来あるべきではないときに至る所で使用されます。彼らはかなりひどいと思いますが、それは主観的です。

2
Abacus

これは、IEEE標準の浮動小数点数と倍精度浮動小数点数に指定された「無限大」の値があるという事実と関係がある可能性があります。 .NETは、ハードウェアレベルですでに存在するものを公開しているだけです。

これが論理的に理にかなっている理由については、kekekelaの回答を参照してください。

1
Brennan Vincent

double型は浮動小数点演算の標準である IEEE 754 に準拠しているため、これは仕様によるものです。 Double.NegativeInfinity および Double.PositiveInfinity のドキュメントを確認してください。

この定数の値は、正の{または負の}数値をゼロで除算した結果です。

1
Wesley Wiser