【问题标题】:What is the most effective way for float and double comparison?浮动和双重比较最有效的方法是什么?
【发布时间】:2010-09-06 06:00:06
【问题描述】:

比较两个double 或两个float 值的最有效方法是什么?

仅仅这样做是不正确的:

bool CompareDoubles1 (double A, double B)
{
   return A == B;
}

但类似:

bool CompareDoubles2 (double A, double B) 
{
   diff = A - B;
   return (diff < EPSILON) && (-diff < EPSILON);
}

似乎浪费了处理。

有人知道更智能的浮点比较器吗?

【问题讨论】:

  • > 在函数的开头添加 ... 会更有效吗? &lt;invoke Knuth&gt;过早的优化是万恶之源。&lt;/invoke Knuth&gt;上面提到的abs(a-b)
  • 原始发布者的实现唯一不理想的是它在 && 处包含一个额外的分支。 OJ 的答案是最佳的。 fabs 是一个内在函数,它是 x87 上的一条指令,我想几乎所有其他指令也是如此。已经接受 OJ 的回答了!
  • 如果可以的话,放弃浮点数并使用定点数。例如,使用 {fixed point} 毫米而不是 {floating point} 米。
  • “仅仅这样做是不正确的” - 这只是垃圾,当然使用== 可能是完全正确的,但这完全取决于未给出的上下文这个问题。在知道上下文之前,== 仍然是“最有效的方式”

标签: c++ algorithm optimization floating-point


【解决方案1】:

如需更深入的方法,请阅读Comparing floating point numbers。这是该链接中的代码 sn-p:

// Usable AlmostEqual function    
bool AlmostEqual2sComplement(float A, float B, int maxUlps)    
{    
    // Make sure maxUlps is non-negative and small enough that the    
    // default NAN won't compare as equal to anything.    
    assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);    
    int aInt = *(int*)&A;    
    // Make aInt lexicographically ordered as a twos-complement int    
    if (aInt < 0)    
        aInt = 0x80000000 - aInt;    
    // Make bInt lexicographically ordered as a twos-complement int    
    int bInt = *(int*)&B;    
    if (bInt < 0)    
        bInt = 0x80000000 - bInt;    
    int intDiff = abs(aInt - bInt);    
    if (intDiff <= maxUlps)    
        return true;    
    return false;    
}

【讨论】:

【解决方案2】:

你写的代码有问题:

return (diff < EPSILON) && (-diff > EPSILON);

正确的代码是:

return (diff < EPSILON) && (diff > -EPSILON);

(......是的,这是不同的)

我想知道在某些情况下晶圆厂是否不会让你失去惰性评估。我会说这取决于编译器。您可能想尝试两者。如果它们平均相等,请使用 fabs 实施。

如果您有一些关于两个浮点数中哪一个更可能大于另一个的信息,您可以按照比较的顺序进行操作,以更好地利用惰性求值。

最后你可能会通过内联这个函数得到更好的结果。不过不太可能改善很多...

编辑:OJ,感谢您更正您的代码。我相应地删除了我的评论

【讨论】:

  • 问题已被编辑为正确。 return (diff &lt; EPSILON) &amp;&amp; (diff &gt; -EPSILON);return (diff &lt; EPSILON) &amp;&amp; (-diff &lt; EPSILON); 都是等价的,而且都是正确的。
猜你喜欢
  • 2015-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多