【问题标题】:When comparing for equality is it okay to use `==`?比较相等时可以使用`==`吗?
【发布时间】:2010-02-11 06:01:58
【问题描述】:

比较相等时可以使用==吗?

例如:

int a = 3;
int b = 4;

如果检查是否相等,你应该使用:

if (a == b)
{
     . . .
}

如果使用浮点数,情况会改变吗?

【问题讨论】:

  • 对于整数 == 就足够了
  • 而且带有 == 的代码更简洁易读。
  • 第二个检验其实是对不等式的检验。
  • @rlbond:感谢您的提示!我删除了第二个测试,而不是修改以保持问题的范围相同。

标签: c++ equality


【解决方案1】:

'==' 非常适合整数值。

您应该比较浮点数是否相等;使用容忍方法:

if (fabs(a - b) < tolerance)
{
   // a and b are equal to within tolerance
}

【讨论】:

  • 请使用晶圆厂!与 abs 比较首先将参数转换为 int ......这等于非常不准确的比较。
  • @Michael abscmath 中的浮点类型进行了重载,Mitch 的代码没有问题。
  • 需要使用std::abs,因为只有那个是重载的。 C 函数 ::abs 不是。我总是明确说明命名空间以避免难以调试的错误,以防它意外选择非重载的 C 函数。
  • 如果有人执行#include 或删除您的“使用命名空间标准”,事情可能会变得非常糟糕。您甚至可能不会收到编译器警告。现在你可能会对脆弱的代码感到满意......我当然不会。
  • 就个人而言,我使用 cmath,但明确限定大多数浮点调用,例如 std::abs()std::ceil()。我需要这个,因为在我的一些应用程序中我使用了一个实数,它是浮点数、双精度数之类的类型定义。
【解决方案2】:

重新浮点数:是的。不要将 == 用于浮点数(或者如果你这样做,就知道你在做什么)。而是使用类似的东西

if (fabs(a - b) < SOME_DELTA) {
  ...
}

编辑:将 abs() 更改为 fabs()

【讨论】:

  • 我永远不会使用 == 来比较浮点数。
  • 请使用晶圆厂!与 abs 比较首先将参数转换为 int ......这等于非常不准确的比较。
  • @Mitch Wheat:这就是为什么 Frank Shearar 提到你应该知道你在做什么。如果你这样做,使用 == 是可以的。请参阅 Goldbergs 的经典“每个计算机科学家都应该了解的浮点数学知识”(docs.sun.com/source/806-3568/ncg_goldberg.html)
  • 谢谢。我读过那篇文章和其他类似的文章(曾经在数值处理领域工作)。我能想到一些适用于浮点数的 == 的情况。
  • 这里也一样。一些可能包括:* 在不同平台上测试随机数生成器以获得相同的结果 * 测试 NaN ((x==x)==false) * 测试无穷大。
【解决方案3】:

进行 比较并不能真正帮助您解决舍入错误。使用 Mark Shearar 给出的解决方案。不过,浮点数的直接相等比较并不总是不好的。如果将某些特定值(例如 0.0 或 1.0)直接分配给变量,则可以使用它们来检查变量是否仍然具有该值。只有在计算之后,舍入误差才会搞砸相等性检查。

请注意,使用 、= 或 == 将 NaN 值与任何值(也可以是另一个 NaN)进行比较会返回 false。 != 返回 true。

【讨论】:

  • @phresnel:如果你的意思是他把“Mark”误认为“Frank”,好吧,让这家伙活下去……
  • @Gorpik:当然,这并不是一种侮辱 :)
【解决方案4】:

在许多类中,operator== 通常实现为(!(a &lt; b || b &lt; a)),因此您应该继续使用 ==。除了浮动,正如米奇小麦上面所说的那样。

【讨论】:

  • 令我惊讶的是,在许多情况下,单个运算符会以 3 个运算符的形式实现。如果它通常按照上面的方式实现,它就可以解释为什么宇宙如此混乱 - a &lt; b &amp;&amp; b &lt; a 总是 false,所以一切都必须相等?
  • 我从未见过编译器为== 生成代码时使用了除单个比较指令之外的任何东西。如果我理解正确,您是说它进行两次比较并检查不是“相等”而是一对小于?
  • rlbond 不是在谈论内置类型,而是在谈论用户类。以这种方式编写 operator== 确实很典型,因为 C++ 中的“标准”比较运算符是 operator
  • 这不是典型的,因为正如邓肯指出的那样,它不起作用。 (!(a&lt;b)) &amp;&amp; (!(b&lt;a))!(a&lt;b || b&lt;a) 都可以工作。但即使这也不是典型的,因为绝大多数课程都可以做得更好。
  • 抱歉,没有注意到原始答案中的错误(确实应该是|| 而不是&amp;&amp;)。无论如何,当 STL 检查等效性时,它通常会使用它,因为在许多情况下只有 operator&lt; 是强制性的。无论如何,这个讨论可能并不真正适用于 OP 的问题。
【解决方案5】:

比较整数时,使用 ==。同时使用“”来检查 int 上的相等性会导致代码变慢,因为它需要两次比较而不是一次,花费双倍的时间。 (虽然编译器可能会为你修复它,但你不应该习惯于编写糟糕的代码)。

请记住,早期的优化很糟糕,但早期的低效代码同样糟糕。

编辑:修正了一些英文...

【讨论】:

  • 好的,所以我们有人反对其他人来宣传他们的遮阳篷?我有 2 次投反对票,没有任何解释,如果你是真正的批评家,你应该看到我是新手,然后应该知道我不知道我做错了什么,但如果你不是真正的批评家,你不应该随意投反对票。
  • 我没有投反对票,但是两次比较产生较慢代码的说法是非常错误的,因为编译器(如您所说)无论如何都会对其进行优化。
  • 所以不是假的。这是真的,但很可能(请记住,我们不知道这个人正在使用什么编译器和多少优化)它会被优化掉。例如,如果这个人正在使用早期的 DOS C 编译器怎么办?我知道人们仍在使用这些(今天有人问了一个问题并提到使用其中一个)
  • @speeder:根据投票拆分(适用于代表超过 1000 名的用户),您获得了 1 票和 0 票。我猜要么 SO 有问题,要么他们收回了反对票。
  • 在某些情况下,客户要求关闭编译器优化(通常是安全关键和/或高可靠性嵌入式系统),因此不允许编译器优化这种特殊情况。您所写的正是将要处理的内容,在这种情况下== 更正确。但即使== 速度较慢,我还是推荐它只是为了便于阅读。降低性能的可读性并观察您的错误率攀升,以及调试时间激增。
【解决方案6】:

对于整数,== 符合您的预期。如果他们是平等的,他们是平等的。

对于花车,这是另一回事。操作产生不精确的结果并且错误累积。处理数字时你需要有点模糊。我用

if ( std::abs( a - b )
    < std::abs( a ) * ( std::numeric_limits<float_t>::epsilon() * error_margin ) )

其中float_t 是一个typedef;这给了我尽可能高的精度(假设 error_margin 计算正确)并允许轻松调整到另一种类型。

此外,一些浮点值不是数字:有无穷大、负无穷大,当然也不是数字。 == 用这些做有趣的事情。 Infinity 等于 infinity,但 not-a-number 不等于 not-a-number。

最后,有正负零,虽然不同但又相等!要将它们分开,您需要检查逆是正无穷还是负无穷。 (只要确保不会出现被零除的异常。)

所以,除非您有更具体的问题,否则我希望能够处理它……

【讨论】:

  • 如果 a 为负数,这不是一个好主意。试试 std::abs(a-b)
  • @Michael:谢谢,已修复。没有必要在 RHS 上添加它们,因为如果它产生差异,比较就会是错误的。 epsilon*(a+a) 和 epsilon*(a+b) 之间的差异小于 a-b 的精度,否则 error_margin 必须选择得足够低以使比较失败。如果要过滤掉超过一半的尾数位,则添加 a+b 可能很重要……无论如何,都需要对实际计算进行一些分析。
  • 我对您更新的比较方法的问题是它不是对称的。即当 b-a 接近缩放容差时,您可以使用 compare(a,b) != compare(b,a) 。我不喜欢这种可能性。
  • @Michael:我认为这不会发生,因为 eps*(2*a) 和 eps*(a+b) 之间的差异仅超出 a-b 的精度。 (a-b) 将在尾数中包含少量数据,与 error_margin 一样多的位,然后是一长串零,如果有机会等式成立的话。添加 a+b 只会改变那些零的比较。看我之前的回复。也许这对于非常大的 error_margins 并不适用。你有具体的例子吗?
  • 我对数学进行了更深入的研究,对于小的 error_margin,我同意你的看法。我想我使用的版本是根据噪声计算得出的值,因此需要较大的容差。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多