http://msdn.microsoft.com/en-us/library/system.dividebyzeroexception.aspxによると 、0 で除算すると Int と Decimal のみが DivideByZeroException をスローしますが、浮動小数点を 0 で除算すると、結果は次のようになります。無限大、負の無限大、または NaN。どうしてこれなの?結果が +ve 無限大、-ve 無限大、または NaN になる例は何ですか?
3 に答える
IEEE 標準化委員会は、浮動小数点演算でこの種の問題が発生する可能性のあるコードの範囲について、例外処理は価値があるよりも面倒であると感じました。
トラップを使用してプログラムを停止できますが、回復不能な状況は非常にまれです。
[...]
フラグは、予測可能な制御フローと速度の両方を提供します。それらを使用するには、プログラマーが例外的な条件を認識している必要がありますが、フラグの粘着性により、プログラマーは必要になるまで例外的な条件の処理を遅らせることができます。
これは、C# のように例外処理が深く組み込まれている言語に慣れている開発者にとっては奇妙に思えるかもしれません。IEEE 754 規格の開発者は、そのような機能が利用できない、または望ましくない、より広範な実装 (組み込みシステムなど) について考えています。
マイケルの答えはもちろん正しいです。ここに別の見方があります。
整数は正確です。整数で 7 を 3 で割ると、実際には「負の数になる前に、7 から 3 を何回引くことができますか?」という質問をしていることになります。0 による除算は定義されていません。7 から 0 を引いて負の数を得ることができる回数はないからです。
フロートは、その性質上不正確です。それらにはある程度の精度があり、「実際の」数量は、指定されたフロートとそれに近いフロートの間のどこかにあると想定するのが最善です。さらに、フロートは通常、物理量を表し、表現誤差よりもはるかに大きな測定誤差を持っています。フロートは、ポイントを囲むぼんやりとした塗りつぶされた領域と考えています。
したがって、float で 7 を 0 で割るときは、7 にかなり近い数値を 0 にかなり近い数値で割ると考えてください。明らかに、合理的にゼロに近い数値は、商を任意に大きくすることができます! したがって、これは答えとして無限を与えることによってあなたに通知されます。これは、真の値が実際にどこにあるかに応じて、答えが任意に大きくなる可能性があることを意味します。
プロセッサに組み込まれている浮動小数点エンジンは、ゼロによる浮動小数点除算の例外を生成することができます。Windows には専用の例外コード STATUS_FLOAT_DIVIDE_BY_ZERO、例外コード 0xC000008E、「ゼロによる浮動小数点除算」があります。オーバーフロー、アンダーフロー、不正確な結果 (別名デノーマル) など、FPU が報告できるその他の事故と同様に。
これを行うかどうかは制御レジスタによって決定され、プログラムは_controlfp()などのヘルパー関数を使用してこのレジスタを変更できます。Borland ツールで作成されたライブラリは、たとえば、これらの例外のマスクを解除するなど、日常的にこれを行っていました。
控えめに言っても、これはうまくいきませんでした。これは、想像できる最悪のグローバル変数です。そのようなライブラリを、ゼロ除算が例外ではなく無限大を生成することを期待する他のライブラリと混在させることは、まったく機能せず、対処するのがほとんど不可能です。
したがって、言語ランタイムがすべての浮動小数点例外をマスクするのが標準になっています。CLRもこれを主張しています。
例外をマスク解除するライブラリを扱うのは難しいですが、ばかげた回避策があります。例外をスローして、再度キャッチできます。CLR 内の例外処理コードは、制御レジスタをリセットします。この例は、この回答に示されています。