35

变量x是具有可能值的 int -1, 0, 1, 2, 3:。哪个表达式会更快(在 CPU 滴答声中):

1. (x < 0)
2. (x == -1)

语言:C/C++,但我想所有其他语言都一样。

PS我个人认为答案是(x < 0)

对大师来说更广泛:如果x-12^30怎么办?

4

12 回答 12

80

这完全取决于您正在为其编译的 ISA,以及编译器优化器的质量。不要过早地优化:首先分析以找到您的瓶颈

也就是说,在 x86 中,您会发现在大多数情况下两者都同样快。在这两种情况下,您都会有比较 ( cmp) 和条件跳转 ( jCC) 指令。但是,对于(x < 0)某些情况,编译器可能会省略cmp指令,从而将您的代码加速一个完整的周期

具体来说,如果该值x存储在寄存器中,并且是最近在 EFLAGS 寄存器中设置符号标志 SF 的算术运算(例如add、 或sub,但还有更多可能性)的结果,则不需要该cmp指令,编译器只能发出一条js指令。当输入为 -1 时,没有简单的jCC指令会跳转。

于 2009-05-26T19:37:28.647 回答
11

试试看!做一百万,或者更好,每个十亿,然后计时。我敢打赌,您的结果没有统计意义,但谁知道——也许在您的平台和编译器上,您可能会找到结果。

这是一个很好的实验,可以让自己相信过早的优化可能不值得你花时间——而且很可能是“万恶之源——至少在编程中”。

于 2009-05-26T19:34:19.040 回答
8

这两个操作都可以在一个 CPU 步骤中完成,因此它们的性能应该相同。

于 2009-05-26T19:27:38.697 回答
8

x < 0 会更快。如果没有别的,它会阻止获取常量 -1 作为操作数。大多数架构都有与零进行比较的特殊说明,因此这也会有所帮助。

于 2009-05-27T04:10:27.093 回答
7

它可能取决于比较之前或之后的操作。例如,如果您在进行比较之前为 x 分配了一个值,那么检查符号标志可能比与特定值进行比较更快。或者 CPU 的分支预测性能可能会受到您选择的比较的影响。

但是,正如其他人所说,这取决于 CPU 架构、内存架构、编译器和许多其他东西,所以没有一般​​的答案。

于 2009-05-26T20:59:42.397 回答
3

无论如何,重要的考虑因素是哪个实际上可以准确地指导您的程序流程,而哪个恰好产生相同的结果?

如果 x 实际上是索引或枚举中的值,那么 -1 将始终是您想要的,或者任何负值都有效?目前,-1 是唯一的负面因素,但这可能会改变。

于 2009-05-26T19:32:39.873 回答
3

你甚至不能断章取义地回答这个问题。如果您尝试一个微不足道的微基准测试,优化器完全有可能将您的代码飘入以太:

// Get time
int x = -1;
for (int i = 0; i < ONE_JILLION; i++) {
    int dummy = (x < 0); // Poof!  Dummy is ignored.
}
// Compute time difference - in the presence of good optimization
// expect this time difference to be close to useless.
于 2009-05-26T19:34:41.897 回答
1

同样,这两个操作通常在 1 个时钟内完成。

于 2009-05-26T19:27:01.863 回答
1

这取决于架构,但 x == -1 更容易出错。x < 0 是要走的路。

于 2009-05-27T09:01:58.773 回答
1

正如其他人所说,可能没有任何区别。比较是 CPU 中的基本操作,芯片设计人员希望尽可能快地进行比较。

但是您可以考虑其他一些事情。分析每个值的频率并按该顺序进行比较。这可以为您节省不少周期。当然,您仍然需要将代码编译为 asm 来验证这一点。

于 2009-05-28T16:41:08.223 回答
1

我相信你相信这是一个真正的耗时。

我想问机器会给出比我们任何人都更可靠的答案。

我发现,即使在你所说的代码中,我的假设也不是很正确。例如,如果这是在一个内部循环中,如果有任何类型的函数调用,即使是编译器插入的不可见的,该调用的成本将占主导地位。

于 2009-05-28T19:42:08.263 回答
1

尼古拉,你写道:

它实际上是高负载程序中的瓶颈算子。这 1-2 个字符串的性能比可读性更有价值......

所有的瓶颈通常都这么小,即使在完美的设计和完美的算法中(尽管没有这样的)。我进行高负荷 DNA 处理,并且非常了解我的领域和算法

如果是这样,为什么不做下一步:

  1. 获取计时器,将其设置为 0;
  2. 用(x < 0)编译你的高负载程序;
  3. 启动您的程序和计时器;
  4. 在程序结束时查看计时器并记住结果1。
  5. 同1;
  6. 用(x == -1)编译你的高负载程序;
  7. 同3;
  8. 在程序结束时查看计时器并记住结果2。
  9. 比较结果 1 和结果 2。

你会得到答案。

于 2009-08-25T06:38:07.230 回答