我知道由于精度误差,测试浮点数是否相等是很危险的,但测试是否为零安全吗? 我可以想到一些情况,例如在算法中优化特殊情况时,您会想要这样做。 问题涉及浮点数,但我认为答案也适用于双精度浮点数。
考虑以下代码:
float factor = calculateFactor();
if(factor != 0.0f)
applyComplexAlgorithm(factor);
我知道由于精度误差,测试浮点数是否相等是很危险的,但测试是否为零安全吗? 我可以想到一些情况,例如在算法中优化特殊情况时,您会想要这样做。 问题涉及浮点数,但我认为答案也适用于双精度浮点数。
考虑以下代码:
float factor = calculateFactor();
if(factor != 0.0f)
applyComplexAlgorithm(factor);
就安全性而言,如果将值明确设置为0.0f,则它将在那里返回true。
但是,从计算结果中得出的值并不能保证完全等于0.0f,因此从这个意义上说,它并不安全。
因此,您实际上是将0.0f作为一种特殊的魔法值来使用,而不是与零进行真正的比较。
不安全,因为calculateFactor()
中的计算可能不会得出0.0,即使它在算术上应该如此。一个简单的例子:(0.4-0.1)-0.3,使用double
进行计算结果是5.551115123125783e-17。
这肯定是安全的,但你必须考虑它对算法的影响。如果您的算法使用factor
作为除数(并且不检查除以零本身),那么在调用applyComplexAlgorithm(factor)
之前检查factor != 0.0f
是完全合理的。
现在,无论是否应该在使用factor
之前检查小于某个epsilon值的值,完全取决于您的代码意义,不能仅通过提供的代码确定。
如果(如您在另一个评论中所暗示的)要使用特殊值0.0f
作为表示特定含义(例如不能计算因子)的标志值,则使用==
进行比较绝对安全。例如,下面的代码使用0.0f
是确定性的,永远不会出现任何舍入误差:
float calculateFactor()
{
int phase = moon_phase();
if (phase == FULL) { // whatever special case requires returning 0.0f
return 0.0f;
} else {
return 1.0 + (phase * phase); // something that is never 0.0f
}
}
float factor = calculateFactor();
if(factor != 0.0f)
applyComplexAlgorithm(factor);