接近零的浮动值会导致被零除的错误吗
Can a near-zero floating value cause a divide-by-zero error?
每个人都知道你不应该直接比较浮点值,而是应该使用一个容差:
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进行比较?
浮点除以零不是错误。它在支持浮点异常的实现上引发浮点异常(除非您正在积极检查,否则这是一个无运算),并具有定义良好的结果:正或负无穷大(如果分子为非零),或NAN(如果分子是零)。
当分母为非零但非常接近零(例如亚正规)时,也有可能得到无穷大(以及溢出异常),但这不是错误。这就是浮点运算的原理。
编辑:请注意,正如Eric在评论中指出的那样,本答案假设了附录F的要求,附录F是C标准的可选部分,详细说明了浮点行为,并将其与IEEE浮点标准保持一致。在没有IEEE算术的情况下,C并没有定义浮点除以零(事实上,所有浮点运算的结果都是实现定义的,可能被定义为完全无意义的,仍然符合C标准),所以如果你正在处理一个不尊重IEEE浮点的古怪C实现,为了回答这个问题,您必须查阅用于实现的文档。
是的,在某些情况下,用小数字除可以产生与用零除相同的效果,包括陷阱。
一些C实现(以及其他一些计算环境)可能以刷新下溢模式执行,尤其是在使用高性能选项的情况下。在这种模式下,除以一个次法线可以得到与除以零相同的结果。当使用矢量(SIMD)指令时,刷新下溢模式并不少见。
次标准数是指浮点格式中指数最小的数字,这些数字非常小,以至于有效位的隐式位是0而不是1。对于IEEE 754,单精度,这是幅度小于2-126的非零数字。对于双精度,它是大小小于2-1022的非零数字。
正确处理亚正常数(根据IEEE 754)需要一些处理器的额外计算时间。为了在不需要时避免这种延迟,处理器可能具有将低于标准操作数转换为零的模式。即使通常的结果是有限的,用一个低于标准的操作数除以一个数字也会产生与除以零相同的结果。
正如其他答案中所指出的,在采用C标准附录F的C实现中,除以零不是错误。并不是所有的实现都启用了。在没有启用的实现中,如果没有关于环境的其他规范,您就无法确定是否启用了浮点陷阱,特别是除以零异常的陷阱。
根据您的情况,您可能还必须防止应用程序中的其他代码更改浮点环境。
要回答帖子标题中的问题,除以一个很小的数字不会导致除以零,但可能会导致结果变成无穷大:
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
只有精确除以0.f才会引发除以零的异常。
然而,除以一个非常小的数字可能会产生溢出异常——结果太大,以至于无法再用浮点表示。除法将返回无穷大。
无穷大的浮点表示可以在计算中使用,因此如果您的其他实现可以处理它,则可能不需要检查它。
在这种情况下,我是否也需要与epsilon进行比较?
您永远不会收到被零除的错误,因为0.0f
正是在IEEE浮点中表示的。
话虽如此,你可能仍然想使用一些宽容度——尽管这完全取决于你的应用程序。如果"零"值是其他数学运算的结果,则可能会得到一个非常小的非零数字,这可能会导致除法后出现意外的结果。如果您想将"接近零"的数字视为零,则公差是合适的。然而,这完全取决于您的应用程序和目标。
如果您的编译器使用IEEE 754标准进行异常处理,那么除以零,以及除以一个小到足以导致溢出的值,都会导致值为+/-infiniti。这可能意味着你可能想要包括对非常小的数字的检查(这会导致你的平台上溢出)。例如,在Windows上,float
和double
都符合规范,这可能会导致一个非常小的除数产生+/-infiniti,就像零值一样。
如果您的编译器/平台没有遵循IEEE 754浮点标准,那么我相信结果是特定于平台的。
- 警告处理为错误这里有什么问题
- "error: no matching function for call to"构造函数错误
- boost::进程间消息队列引发错误
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- QT在错误的班级中寻找空位
- vector.resize()中的分配错误
- 代码在main()中运行,但在函数中出现错误
- 释放错误后堆使用
- (C++)分析树以计算返回错误值的简单算术表达式
- Project Euler问题4的错误解决方案
- 我的字符计数代码计算错误.为什么
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 尝试导入pybind-opencv模块时出现libgtk错误
- 3 与错误最接近的总和:字符串常量之前的预期非限定 id
- 接近零的浮动值会导致被零除的错误吗
- SQL 错误:接近 ".2016":语法错误
- n维中最接近对的错误
- GTest浮动更少或接近绝对错误
- C++11:`错误:代码中')'标记之前应有主表达式',用于行扫描以查找最接近的对