接近零的浮点值会导致被零除的错误吗?

大家都知道您不应该直接比较浮点数,而应该使用公差:

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

我想知道在除法使用值之前将值与零进行比较是否同样适用。

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

在这种情况下,我还需要与epsilon进行比较吗?

neuviemeporte asked 2019-10-07T21:04:06Z
5个解决方案
67 votes

浮点除以零不是错误。 它在支持浮点异常的实现上引发一个浮点异常(除非您正在积极检查它们,否则它是一个空操作),并且具有明确定义的结果:正无穷大或负无穷大(如果分子非零),或者 NAN(如果分子为零)。

当分母为非零但非常接近零(例如次法线)时,也有可能获得无穷大(以及溢出异常),但这同样不是错误。 这就是浮点的工作原理。

编辑:请注意,正如Eric在评论中所指出的那样,此答案假定附件F的要求,附件F是C标准的可选部分,详细说明了浮点行为并将其与IEEE标准的浮点对齐。 在没有IEEE算术的情况下,C不会将浮点除以零(事实上,所有浮点运算的结果都是实现定义的,可以定义为完全废话,仍然符合C标准),因此如果 如果您要处理的是一个不符合IEEE浮点数的奇特C实现,则必须参考用于回答此问题的实现的文档。

R.. answered 2019-10-07T21:04:33Z
24 votes

是的,在某些情况下,除以小数可以产生与除以零(包括陷阱)相同的效果。

某些C实现(和某些其他计算环境)可能在刷新下溢模式下执行,尤其是在使用高性能选项的情况下。 在这种模式下,除以非正规数可以得到与除以零相同的结果。 使用向量(SIMD)指令时,冲洗下溢模式并不罕见。

非正规数是那些浮点格式中具有最小指数的数字,它们是如此之小,以至于有效位数的隐含位是0而不是1。对于IEEE 754,单精度,这是大小小于2的非零数字 -126。 对于双精度,它是大小小于2-1022的非零数字。

正确处理非正规数(根据IEEE 754)在某些处理器中需要额外的计算时间。 为了避免不必要时的这种延迟,处理器可以采用一种将非标准操作数转换为零的模式。 即使将通常的结果是有限的,将数字除以非正规操作数也将产生与除以零相同的结果。

正如在其他答案中指出的那样,在采用C标准附件F的C实现中,除以零并不是错误。 并非所有实现都可以。 在没有实现的情况下,如果没有有关环境的其他规范,则无法确定是否启用了浮点陷阱,尤其是除零异常的陷阱。

根据您的情况,您可能还必须防止应用程序中的其他代码更改浮点环境。

Eric Postpischil answered 2019-10-07T21:05:31Z
9 votes

要回答帖子标题中的问题,除以很小的数字不会导致除以零,但是可能导致结果变为无穷大:

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
dasblinkenlight answered 2019-10-07T21:06:01Z
7 votes

只有精确地除以0.f会引发被零除的异常。

但是,除以非常小的数字会产生溢出异常-结果太大,以致不能再用浮点数表示。 除法将返回无穷大。

可以在计算中使用无穷大的float表示形式,因此,如果实现的其余部分可以处理它,则可能无需检查它。

Jens Agby answered 2019-10-07T21:06:38Z
3 votes

在这种情况下,我还需要与epsilon进行比较吗?

您将永远不会收到除以零的错误,因为2559275608064964918528精确地表示为IEEE浮点数。

话虽如此,您可能仍想使用一些公差-尽管这完全取决于您的应用程序。 如果“零”值是其他数学运算的结果,则有可能获得非常小的非零数字,这可能导致除法后的意外结果。 如果要将“接近零”的数字视为零,则公差是合适的。 但是,这完全取决于您的应用程序和目标。

如果您的编译器使用IEEE 754标准进行异常处理,则除以零,以及除以足以引起溢出的较小值,都将导致+/- infiniti值。 这可能意味着您可能希望包括对非常小的数字的检查(这将导致平台溢出)。 例如,在Windows上,float和2559275608064918518529都符合规范,这可能导致很小的除数创建+/-无限,就像零值一样。

如果您的编译器/平台未遵循IEEE 754浮点标准,那么我相信结果是特定于平台的。

Reed Copsey answered 2019-10-07T21:07:25Z
translate from https://stackoverflow.com:/questions/12114498/can-a-near-zero-floating-value-cause-a-divide-by-zero-error