【问题标题】:What is faster (x < 0) or (x == -1)?(x < 0) 或 (x == -1) 哪个更快?
【发布时间】:2010-10-29 01:48:33
【问题描述】:

变量x 是具有可能值的整数:-1, 0, 1, 2, 3。 哪个表达式会更快(以 CPU 计时):

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

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

附:我个人认为答案是(x &lt; 0)

对于大师来说更广泛:如果 x-12^30

【问题讨论】:

  • 要回答如此低级的考虑,CPU 架构将是一个最小的信息,你不觉得吗?但即便如此,在这些条件下需要不同数量的周期的 CPU 还是相当原始的。
  • 为什么这是一个糟糕的问题?一个彻底的答案让所有与更好地理解处理器如何工作以及类似的东西相关联。这不是一件好事吗?
  • 最后一点:没有办法概括这样的问题的答案。最好的方法是用你的生产编译器和一个有代表性的测试系统来尝试这两种方法,然后比较结果。我很惊讶这种问题出现的频率如此之高,而几分钟的基准测试可以提供答案。
  • 我相信他只是想知道更多。优化这个是愚蠢的。我自己其实很感兴趣,因为我不知道。 +1 来自我 :)
  • @Ismael:听起来你从来没有处理过嵌入式代码。

标签: c++ c performance optimization cpu


【解决方案1】:

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

这是一个很好的实验,可以让自己相信过早的优化可能不值得你花时间——而且很可能是“the root of all evil--at least in programming”。

【讨论】:

  • 这是建议,但不是真正的答案。
【解决方案2】:

尼古拉,你写:

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

所有的瓶颈通常都是这个 小,即使在完美的设计与 完美的算法(虽然没有 这样的)。我做高负荷DNA处理 了解我的领域和算法 挺好的

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

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

你会得到答案的。

【讨论】:

    【解决方案3】:

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

    但是,正如其他人所说,这取决于 CPU 架构、内存架构、编译器和许多其他东西,因此没有通用答案。

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

          【解决方案6】:

          这取决于架构,但 x == -1 更容易出错。 x

          【讨论】:

          • 不,这不是要走的路。要检测错误,请使用单元测试,而不是花哨的代码。为了更不容易出错:给常量命名。通常最好直奔主题。如果目标是与 -1 进行比较,只需编写 (x == -1),否则下一个维护此代码的开发人员将不得不弄清楚我们为什么要与 0 进行比较(“哦,好吧,实际上是针对-1"),然后找出 (f...) 是什么 -1。
          • 好吧,我们在谈论一个理想的案例。正如您所说,没有人应该使用“幻数”,而是使用常量。您可以通过这种方式与 ( x
          【解决方案7】:

          x

          【讨论】:

          • 在不了解架构和/或编译器的情况下,你怎么知道这一点?
          • 你说的是哪种架构?我相信大多数 x86 指令集都可以与立即值进行比较。无需获取操作数。这是英特尔指令集参考的链接:intel.com/Assets/PDF/manual/253666.pdf
          • 当然,几乎任何架构都可以与即时值进行比较。但即使在那里,指令也更大(因此需要从内存中再次提取)。没什么大不了的,除非每一盎司的性能都很关键,这似乎是这里的背景。我假设提问者正在编写设备驱动程序或其他东西。
          • 关于第一个问题 - 我已经研究架构很长时间了。在前半打左右之后,模式开始出现。我也碰巧对 x86 指令集的语义了解得更多,现在大多数人都倾向于关注它。例如,任何时候您在 x86 上对某个值执行任何操作时,都会设置条件位。因此,您可以在进行计算、将值加载到寄存器等之后使用 JB 指令测试是否定的。编译器通常会尝试利用这一点,尽管有些愚蠢的编译器不会。
          【解决方案8】:

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

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

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

          【讨论】:

          • 我不相信这是或曾经是任何程序中的“瓶颈”。如果您看到时间上的差异,则更有可能您将代码“跳过”在 == -1 条件上,例如将其设置为 -2,因此不会终止循环(假设表达式是循环的一部分)。
          • 不要忘记 cmp 指令可能会被 or 指令取代,这不会减少周期数,但可能会改变内存对齐方式。这可能会有所帮助,也可能会适得其反,这就是分析如此重要的原因。
          • P.S.不要小看这个问题——我的循环太紧了,这种优化会有所作为。通常只有百分之几,但有时每一点都有帮助!
          • 在 x86 上,TEST 可用于测试 reg == 0,预计比 CMP 更快。
          • 甚至不仅仅依赖于ISA,还依赖于架构的实际实现......
          【解决方案9】:

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

          // 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.
          

          【讨论】:

          • 它会被编译器优化成零指令。但我理解你的想法,谢谢。
          • 是的——这就是我想说的。如果第一次尝试不清楚,那是我的错。
          • 您可以通过允许 x 和 dummy 转义(即,将它们的指针传递给另一个翻译单元中的函数)并引入编译器特定的内存屏障指令(例如 gcc 的 __sync_synchronize( )。这将强制编译器发出代码来评估 (x
          • 最后,您将最终创建一个精心构建的结构,以尝试测量不存在或在没有 100% 上下文的情况下无法测量的差异。例如,OP 用“C++”和“C”标记了这个问题——两者之间存在巨大差异,更不用说在所有不同平台上的各种编译器之间了。
          • 在这么小的一段代码中添加测量代码可能会因为缓存、优化等而改变结果。
          【解决方案10】:

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

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

          【讨论】:

            【解决方案11】:

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

            【讨论】:

            • 啊!虽然这在绝大多数芯片上都是正确的,但您在不知道他正在开发的平台的情况下,无法做出明确的声明。整个世界都不是 x86。
            • 好吧,我假设如果他问这个问题是为了一个特定的、非正常的架构,他会这样指定。如果他问的是笼统的问题,我试图为大多数现代架构给出一个简单的答案。
            • 当然,我没有考虑任何特定的架构。普通 x86。
            【解决方案12】:

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

            【讨论】:

            • 这将是一个指令获取和执行周期,而不是一个时钟周期。
            猜你喜欢
            • 2014-01-13
            • 2011-09-22
            • 2016-03-16
            • 2010-09-24
            • 1970-01-01
            • 2017-01-19
            • 1970-01-01
            • 1970-01-01
            • 2019-08-02
            相关资源
            最近更新 更多