接近于零的浮点值可能会导致一个除以零错误?(Can a near-zero floating val

2019-07-31 03:51发布

大家都知道你是不应该直接使用公差比较花车,而是:

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

我想知道是否同样适用于在分割使用它之前的值进行比较为零。

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

难道我还需要在这种情况下,小量比较?

Answer 1:

通过零浮点除法是不是一个错误。 它提出了一个浮点异常(这是一个空操作,除非你正在积极检查他们)在支持浮点异常实现,并具有良好定义的结果是:正或负无穷大(如果分子不为零),或NAN(如果分子为零)。

它也可能得到无穷大(溢出异常)作为结果,当分母为零,但非常接近于零(例如低于正常),但这又不是一个错误。 这点是多么的浮动工作。

编辑:需要注意的是,埃里克在评论中指出的那样,这个答案假定的附件F,C标准的细节浮点行为,并与浮点IEEE标准对准它的可选部分的要求。 在不存在IEEE算术的,C没有定义零浮点除法(事实上,所有浮点操作的结果是实现定义的,并且可以被定义为完全无义,并且仍然符合标准C),因此,如果你处理稀奇古怪的C语言实现,不兑现IEEE浮点,你必须请查询您正使用来回答这个问题落实的文档。



Answer 2:

是的,小的数字除以可引起相同的效果,除零,包括陷阱,在某些情况下。

一些C实现(以及某些其他计算环境)可以在冲洗下溢模式下执行,尤其是在使用高性能的选项。 在这种模式下,通过反规范分割可以导致相同的结果除以零。 当使用载体(SIMD)指令冲洗下溢模式的情况并不少见。

反规范数是那些在浮点格式的最小指数,其是如此之小,有效数的隐含位为0,而不是1。对于IEEE 754单精度,这是与幅度非零数小于2 -126。 对于双精度,它与幅度小于2 -1022非零数字。

正确处理反规范数(在根据IEEE 754)需要在一些处理器中的额外的计算时间。 为了避免在不需要的时候这种延迟,处理器可以具有其将非正规操作数为零的模式。 然后通过反规范操作数除以数会产生相同的结果除以零,即使通常的结果将是有限的。

在其他的答案所指出的,被零除是不是在C实现,采用C标准的附录F的误差。 不就是所有实现。 在不实现,你不能确定浮点陷阱是否已启用,特别是对于除以零异常的陷阱,没有关于环境的其他规格。

根据您的情况,您可能还需要提防其他代码在应用程序中改变浮点环境。



Answer 3:

要回答你的文章的标题问题,由一个非常小的数目除以不会被零造成分裂,但它可能会导致的结果变得无穷大:

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


Answer 4:

只有分工正好0.f将零异常养师。

然而,一个非常小的数目划分可产生溢出例外 - 结果是如此之大,它不再能够通过浮法来表示。 该部门将返回无穷大。

无穷大的浮点表示可以在计算中使用,因此有可能不是一个需要检查它,如果你执行的其他可以处理它。



Answer 5:

难道我还需要在这种情况下,小量比较?

零错误你永远不会收到一个鸿沟,为0.0f是在准确表示IEEE浮点 。

这就是说,你可能仍然要使用一些宽容 - 尽管这完全取决于你的应用。 如果“零”值是其它数学运算的结果,有可能得到一个非常小的,非零的数字,这可能会导致您的分裂后一个意想不到的结果。 如果你要正确对待“接近零”的数字为零,公差是适当的。 这完全取决于你的应用程序和目标,但是。

如果你的编译器使用IEEE 754个标准进行异常处理 ,然后除以零,以及由值小到足以导致溢出一个部门,都将导致+/-英菲尼迪的值。 这可能意味着你可能要包括非常小的数字的检查(这将导致你的平台上的溢出)。 例如,在视窗 , floatdouble都符合规范,这可能会导致一个非常小的除数,以创建+/-英菲尼迪,就像一个零值。

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



文章来源: Can a near-zero floating value cause a divide-by-zero error?