63

フロートを直接比較するのではなく、許容値を使用することになっていることは誰もが知っています。

float a,b;
float epsilon = 1e-6f;
bool equal = (fabs(a-b) < epsilon);

値を除算で使用する前に値をゼロと比較する場合にも同じことが当てはまるかどうか疑問に思っていました。

float a, b;
if (a != 0.0f) b = 1/a; // oops?

この場合、イプシロンと比較する必要がありますか?

4

5 に答える 5

69

浮動小数点のゼロ除算はエラーではありません。浮動小数点例外をサポートする実装で浮動小数点例外(アクティブにチェックしていない限りノーオペレーション)が発生し、正または負の無限大(分子がゼロ以外の場合)、または明確に定義された結果が得られます。 NAN(分子がゼロの場合)。

分母がゼロ以外であるがゼロに非常に近い場合(たとえば、異常)の結果として無限大(およびオーバーフロー例外)を取得することも可能ですが、これもエラーではありません。これが浮動小数点のしくみです。

編集: Ericがコメントで指摘しているように、この回答は、浮動小数点の動作を詳述し、浮動小数点のIEEE標準に合わせるC標準のオプション部分であるAnnexFの要件を前提としていることに注意してください。IEEE演算がない場合、Cは浮動小数点のゼロ除算を定義しません(実際、すべての浮動小数点演算の結果は実装定義であり、完全にナンセンスとして定義され、C標準に準拠している可能性があります)。 IEEE浮動小数点を尊重しない風変わりなC実装を扱っている場合は、この質問に答えるために使用している実装のドキュメントを参照する必要があります。

于 2012-08-24T18:17:45.703 に答える
26

はい、小さな数で割ると、状況によっては、トラップを含め、0 で割った場合と同じ結果になることがあります。

一部の C 実装 (およびその他のコンピューティング環境) は、特に高パフォーマンスのオプションが使用されている場合に、フラッシュ アンダーフロー モードで実行される場合があります。このモードでは、サブノーマルで除算すると、ゼロで除算した場合と同じ結果になる可能性があります。ベクター (SIMD) 命令を使用する場合、フラッシュ アンダーフロー モードは珍しくありません。

非正規数とは、浮動小数点形式の最小指数を持つもので、仮数の暗黙のビットが 1 ではなく 0 になるほど小さいものです。-126 . 倍精度の場合、大きさが 2 -1022未満のゼロ以外の数値です。

非正規数を (IEEE 754 に従って) 正しく処理するには、一部のプロセッサで追加の計算時間が必要になります。必要のないときにこの遅延を回避するために、プロセッサには非正規オペランドをゼロに変換するモードがある場合があります。数値を非正規オペランドで除算すると、通常の結果が有限であっても、ゼロで除算した場合と同じ結果になります。

他の回答で述べたように、ゼロで割ることは、C 標準の Annex F を採用する C 実装ではエラーではありません。すべての実装がそうするわけではありません。そうでない実装では、環境に関する追加の仕様がないと、浮動小数点トラップ (特にゼロ除算例外のトラップ) が有効になっているかどうかを確認できません。

状況によっては、アプリケーション内の他のコードが浮動小数点環境を変更しないようにする必要がある場合もあります。

于 2012-08-24T19:04:49.350 に答える
9

あなたの投稿のタイトルの質問に答えるために、非常に小さい数で割ってもゼロによる除算は発生しませんが、結果が無限大になる可能性があります。

double x = 1E-300;
cout << x << endl;
double y = 1E300;
cout << y << endl;
double z = y / x;
cout << z << endl;
cout << (z == std::numeric_limits<double>::infinity()) << endl;

これにより、次の出力が生成されます。

1e-300
1e+300
inf
1
于 2012-08-24T18:19:03.873 に答える
8

正確に 0.f による除算のみがゼロによる除算の例外を発生させます。

ただし、非常に小さい数で除算すると、オーバーフロー例外が発生する可能性があります。結果が大きすぎて、浮動小数点数で表すことができなくなります。除算は無限大を返します。

無限大の float 表現は計算で使用できるため、残りの実装で処理できるかどうかを確認する必要がない場合があります。

于 2012-08-24T18:20:30.257 に答える
3

この場合、イプシロンと比較する必要がありますか?

IEEE float0.0fで正確に表されるように、ゼロ除算エラーを受け取ることはありません。

そうは言っても、アプリケーションに完全に依存しますが、ある程度の許容範囲を使用したい場合があります。「ゼロ」値が他の数学の結果である場合、ゼロ以外の非常に小さな数値が得られる可能性があり、除算後に予期しない結果が生じる可能性があります。「ほぼゼロ」の数値をゼロとして扱いたい場合は、許容範囲が適切です。ただし、これはアプリケーションと目標に完全に依存します。

コンパイラが例外処理に IEEE 754 標準を使用している場合、ゼロで除算するだけでなく、オーバーフローを引き起こすほど小さい値で除算すると、どちらも +/- 無限大の値になります。これは、非常に小さい数値のチェックを含めることができることを意味します (プラットフォームでオーバーフローが発生する可能性があります)。たとえば、Windowsではfloatdouble両方とも仕様に準拠しているため、ゼロ値のように、非常に小さな除数で +/- 無限大が作成される可能性があります。

コンパイラ/プラットフォームが IEEE 754 浮動小数点標準に従っていない場合、結果はプラットフォーム固有のものになると思います。

于 2012-08-24T18:08:41.780 に答える