零防止除法:检查除数的表达式不会导致零与检查除数不为零?

时间:2012-10-10 17:58:00

标签: c++ floating-point floating-accuracy floating-point-precision divide-by-zero

由于减法中的浮点误差,在以下情况下是否可以除零?

float x, y, z;
...
if (y != 1.0)
    z = x / (y - 1.0);

换句话说,以下是否更安全?

float divisor = y - 1.0;
if (divisor != 0.0)
    z = x / divisor;

3 个答案:

答案 0 :(得分:6)

假设IEEE-754浮点数,它们是等价的。

这是FP算法的基本定理,对于有限x和y,x - y == 0当且仅当x == y时,假设逐渐下溢。

如果将次正规结果刷新为零(而不是逐渐下溢),则该定理仅在结果x-y正常时才成立。因为1.0被很好地缩放,所以y - 1.0永远不会是正常的,所以y - 1.0当且仅当y恰好是1.0时才为零,无论如何处理下溢。

当然,C ++并不保证IEEE-754,但对于大多数“合理的”浮点系统来说,这个定理都是正确的。

答案 1 :(得分:5)

这样可以防止您正好除以零,但这并不意味着结果仍然不会以+/-inf结束。分母可能仍然足够小,因此double无法表示答案,最终会得到inf。例如:

#include <iostream>
#include <limits>

int main(int argc, char const *argv[])
{
    double small = std::numeric_limits<double>::epsilon();
    double large = std::numeric_limits<double>::max() / small;
    std::cout << "small: " << small << std::endl;
    std::cout << "large: " << large << std::endl;
    return 0;
}

在此计划small中,large非零,但它很小,double超出inf的范围且为{{1}}。

答案 2 :(得分:2)

两个代码片段之间没有区别() - 事实上,优化器甚至可以将两个片段优化为相同的二进制代码,假设没有进一步使用divisor变量。

但请注意,按浮点零0.0除法不会导致运行时错误,但会生成inf-inf