测试浮点数是否等于0.0安全吗?

8

我知道由于精度误差,测试浮点数是否相等是很危险的,但测试是否为零安全吗? 我可以想到一些情况,例如在算法中优化特殊情况时,您会想要这样做。 问题涉及浮点数,但我认为答案也适用于双精度浮点数。

考虑以下代码:

float factor = calculateFactor();
if(factor != 0.0f)
    applyComplexAlgorithm(factor);

我不会仅仅为了有一个被接受的答案而接受答案,实际上必须有一个我认为完全回答了问题的答案。 - Emil Eriksson
3个回答

10

就安全性而言,如果将值明确设置为0.0f,则它将在那里返回true。

但是,从计算结果中得出的值并不能保证完全等于0.0f,因此从这个意义上说,它并不安全。

因此,您实际上是将0.0f作为一种特殊的魔法值来使用,而不是与零进行真正的比较。


好的,这是一个不好的例子。在这种情况下,我真正想表达的是使用0.0f作为特殊值进行比较,这将被明确设置。我不知道为什么会想到这个例子,因为这甚至不是我要做的事情。 - Emil Eriksson
明白了。但是,避免在“常规”值中散布魔术值。它们会影响可发现性(例如,当您查看函数签名时,不明显它告诉您除因子外的任何内容),并且在测试(和使用!)API时也会使其更加复杂。相反,尝试重构,使此条件公开为另一个API,或者至少在API调用中明显(后者不太有用)。 - supermem613

6

不安全,因为calculateFactor()中的计算可能不会得出0.0,即使它在算术上应该如此。一个简单的例子:(0.4-0.1)-0.3,使用double进行计算结果是5.551115123125783e-17。


4

这肯定是安全的,但你必须考虑它对算法的影响。如果您的算法使用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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接