除数が被除数よりもはるかに小さい場合にのみ除算アンダーフローが発生するのはなぜですか。被除数のサイズに関係なく、分母がゼロに十分近いときに発生するのではないでしょうか。
1 に答える
http://www.strw.leidenuniv.nl/docs/intel/f_ug/ieee_ovw.htmから
丸められた結果の指数が小さすぎて結果の浮動小数点形式で表すことができない場合、アンダーフロー例外が発生します。
これは、イプシロンなどの特定の値に依存するのではなく、被除数と除数の比率が浮動小数点形式の精度を超えるほど小さい場合にエラーが発生することを意味します。
分母がゼロに近づくと、分子がゼロ以外であると仮定すると、除算の結果は無限大に近づきます。分子がゼロに近づくと、分母がゼロ以外であると仮定すると、結果はゼロに近づきます。この値が十分に小さくなると、発生します。
分子と分母の値が非常に近い場合、たとえそれらが非常に小さくても、有用な結果を得ることができるため、分子が非常に小さいと必ずしもアンダーフローが発生するわけではありません。
例:
C#では、イプシロンは1.401298E-45です。
イプシロン/イプシロン==1.0f
分子は非常に小さいですが、結果は依然として有効なフロートです。
さて、あなたがこのようなことを試みるとしたら:
float max = 3.40282347E+38f;
/// underflow, denominator will be 0.0f
float denominator = epsilon / max;
denominator
1e-83の注文があります。83は最大単精度浮動小数点指数をはるかに超えているため、値はゼロにクランプされます。ここでアンダーフローが発生します。
/// generates a divide-by-zero error.
float result = 10 / denominator;
これにより、無限大ではなくゼロ除算が生成されます。これは、に格納されている中間結果denominator
が最初に0にクランプされてから、2番目の操作で使用されるためです。
アンダーフローまたはゼロ除算のどちらを取得するかは、コンパイラ、括弧の使用と順序などによって異なります。
たとえば、C#でも次のようになります。
10f / float.Epsilon / float.MaxValue
と同様
(10f / float.Epsilon) / float.MaxValue
20971522.0fを与えます。
ただし、数学的に同等の式:
10f / (float.Epsilon / float.MaxValue)
インフィニティを与えます。