web-dev-qa-db-ja.com

ゼロ除算:Cおよび/またはC ++で定義された未定義の動作または実装?

ゼロ除算に関して、基準は次のように述べています。

C99 6.5.5p5- /演算子の結果は、最初のオペランドを2番目のオペランドで除算した商です。 %演算子の結果は剰余です。どちらの操作でも、第2オペランドの値がゼロの場合、動作は定義されていません。

C++ 03 5.6.4-二項/演算子は商を生成し、二項%演算子は、最初の式を2番目の式で除算した余りを生成します。 /または%の第2オペランドがゼロの場合、動作は定義されていません。

上記の段落を額面通りに受け取るとすると、答えは明らかに両方の言語の未定義の振る舞いです。ただし、C99標準をさらに下に見ると、矛盾しているように見える次の段落があります(1)。

C99 7.12p4-マクロINFINITYは、正または符号なしの無限大を表すfloat型の定数式に展開されます(使用可能な場合)。

標準には、未定義の振る舞いを(潜在的に)矛盾するステートメントに置き換えることができない、ある種の黄金律がありますか?それを除けば、実装でINFINITYマクロが定義されている場合、ゼロ除算がそのように定義されていると結論付けるのは不合理ではないと思います。ただし、実装でそのようなマクロがnot定義されていない場合、動作は未定義です。

2つの言語のそれぞれについて、この問題に関するコンセンサス(ある場合)が何であるかを知りたいです。整数除算int i = 1 / 0と浮動小数点除算float i = 1.0 / 0.0について話している場合、答えは変わりますか?

注(1) C++ 03標準では、INFINITYマクロを含む<cmath>ライブラリについて説明しています。

24
SiegeX

矛盾は見られません。ゼロによる除算は未定義の期間です。 "... INFINITYが定義されていない限り"引用されたテキストのどこにも言及されていません。

数学のどこにも1/0 = 無限大と定義されていないことに注意してください。 1つかもしれないそれをそのように解釈しますが、それは健全な事実ではなく、個人的な「ショートカット」スタイルの解釈です。

25
Péter Török

1/0は無限大ではなく、

lim 1/x =∞(x-> +0)
11

これは数学で最も純粋な質問ではなく、C/C++の質問でした。

  • 最新のすべてのCコンパイラ/ FPUが使用しているIEEE754標準によると、[.____]があります。
    • 3.0/0.0 = INF
    • 0.0/0.0 = NaN
    • -3.0/0.0 = -INF

FPUには、必要に応じて例外を生成するように設定できるステータスフラグがありますが、これは標準ではありません。

INFが有用な結果である場合、INFは分岐を回避するのに非常に役立ちます。ここでの説明を参照してください。

http://people.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF

5
wcochran

なぜですか?

これは数学的には意味がありません。一般に、1 /xが∞として定義されているわけではありません。また、少なくともさらに2つのケースが必要になります:-1 /xと0 /x∞に等しくすることもできません。

ゼロ除算 一般、および コンピューター演算 に関するセクションを参照してください。

4
unwind

__STDC_IEC_559__を定義する実装は、付録Fに記載されている要件に従う必要があります。これには、IEC 60559と一致する浮動小数点セマンティクスが必要です。標準では、浮動小数点の動作に要件はありません。 __STDC_IEC_559__を定義しない実装ではゼロによるゼロ除算をポイントしますが、それを定義する実装ではゼロ除算を行います。 IEC 60559で動作が指定されているが、C標準で指定されていない場合、C標準ではIEC標準で説明されているように動作するように__STDC_IEC_559__を定義するコンパイラが必要です。 。

IEC 60559(または米国標準IEEE-754)で定義されているように、ゼロをゼロで除算するとNaNが生成され、浮動小数点数を正のゼロまたは文字通りの定数ゼロで除算するとINFが生成されます。 _は、被除数と同じ符号の値であり、浮動小数点数を負のゼロで除算すると、反対の符号のINFが生成されます。

1
supercat

INFINITYマクロの場合:IEEE754標準には+/-無限大を表す明示的なコーディングがあります。これは、すべての指数ビットが設定され、すべての小数ビットがクリアされている場合です(小数ビットが設定されている場合、NaNを表します)。

私のコンパイラでは、(int) INFINITY == -2147483648なので、int i = 1/0と評価される式は、INFINITIYが返された場合、間違いなく間違った結果を生成します。

1
king_nak

私はC99ドラフトしか持っていません。 §7.12/ 4では次のように述べています。

マクロ

    INFINITY

可能な場合は、正または符号なしの無限大を表すfloat型の定数式に展開されます。それ以外の場合は、変換時にオーバーフローするfloat型の正の定数になります。

INFINITYは、必ずしもゼロ除算ではなく、浮動小数点オーバーフローの観点から定義できることに注意してください。

1
kennytm

結論として、C99(引用による)は、「実装定義」のコンテキストではINFINITYについて何も述べていません。第二に、あなたが引用したものは、「未定義の振る舞い」の一貫性のない意味を示していません。


[ウィキペディアの未定義の振る舞いのページを引用] "CおよびC++では、実装定義の振る舞いも使用され、言語標準では動作が指定されていませんただし、実装は動作を選択する必要があり、文書化する必要がありますおよび選択したルールを遵守してください。」

より正確には、「実装定義」は標準の特定の属性であるため、標準は、作成されたステートメントに関してこれらの単語を使用する場合、「実装定義」(私は思う)を意味します。 C99 7.12p4の引用では、「実装定義」については言及されていませんでした。

[C99 std(後期ドラフト)から]「未定義の動作:この国際規格が要件を課していない、移植不可能または誤ったプログラム構成または誤ったデータの使用時の動作」

未定義の動作には「要件なし」が課せられることに注意してください。

[C99 ..]「実装定義の動作:各実装が選択の方法を文書化する不特定の動作」

[C99 ..]「不特定の動作:不特定の値の使用、またはこの国際規格が2つ以上の可能性を提供し、どのような場合でも選択される要件を課さないその他の動作」

ドキュメントは、実装で定義された動作の要件です。

0
Jose_X