2

为什么除数下溢仅在除数远小于被除数时引起,无论除数大小如何,分母都足够接近零时不应该发生?

4

1 回答 1

3

来自http://www.strw.leidenuiv.nl/docs/intel/f_ug/ieee_ovw.htm

如果舍入结果的指数太小而无法使用结果的浮点格式表示,则会发生下溢异常。

这意味着当被除数和除数的比率小到足以超过浮点格式的精度时,就会发生错误,而不是依赖于特定值(例如 epsilon)。

当分母接近零时,假设分子非零,除法的结果将接近无穷大。当分子接近零时,假设分母非零,结果接近零。当这个值变得足够小时,就会发生。

如果分子和分母的值非常接近,即使它们非常小,也可以获得有用的结果,因此非常小的分子不一定会导致下溢。

示例

在 C# 中,epsilon 是 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。

是下溢还是被零除取决于编译器、您的使用和括号的顺序等。

例如,再次在 C# 中:

10f / float.Epsilon / float.MaxValue

(10f / float.Epsilon) / float.MaxValue

给出 20971522.0f。

然而,数学上等价的表达式:

10f / (float.Epsilon / float.MaxValue)

给出无穷大。

于 2012-01-13T17:11:44.557 回答