【问题标题】:Is the inequality operator faster than the equality operator?不等式运算符比等式运算符快吗?
【发布时间】:2010-11-05 00:36:07
【问题描述】:

我知道这是一个微优化,所以我纯粹出于好奇而问。

从逻辑上讲,微处理器不需要比较相等运算符的两个操作数的所有位来确定“FALSE”结果。

注意,这是与编程相关的,因为它会影响程序的执行速度。

【问题讨论】:

  • 逻辑上,微处理器不需要比较相等运算符的两个操作数的所有位来确定“FALSE”结果。
  • @Jonathan Wakely。哎呀。感谢您指出了这一点。我编辑了这个问题以解决这个问题。
  • 我想你没有注意到我说的是 equalityFALSE 而不是 inequality正确。我的意思是CPU可以检测到两个值不相等而不看所有位,但是无论您使用==还是!=发现它们不相等都没有关系,所以这两个运算符正好相等的。没有理由认为一个比另一个快。
  • @Jonathan Wakely。你是对的,我看错了你说的。
  • Is < faster than <=?的可能重复

标签: optimization performance cpu-speed


【解决方案1】:

通常,微处理器使用电子门进行比较,而不是像那样逐步进行比较。它一次检查所有位。

【讨论】:

  • 不过,这取决于您要编译的架构。作为一般情况下 cpu 是的,它可以工作,但对于嵌入式微控制器来说,它不是那么容易做出的选择。
【解决方案2】:

这取决于您的平台,但一般情况下,它的性能相同。

例如,在 X86 上,您可以通过查看汇编的工作原理来了解这一点。查看X86 assembly control flow operations - 无论您是在做相等还是不相等,它都是作为 2 个操作完成的。

首先,您执行 CMP(比较)操作。然后,您检查比较是否相等、不相等等。这只是检查比较的结果 - 在这两种情况下,您都在执行 2 次操作。

然而,在许多高级编程语言中,情况有所不同。许多语言根据相等性来定义不等式——要检查不等式,您先进行相等性检查,然后再检查它是否为假。这导致这些语言中的平等(微观上)更快。许多语言也允许您专门编写两者 - 但许多人倾向于用相等来编写不等式,这再次使等式通常稍微快一些。

【讨论】:

  • 额外的好处是,比较一个值是否等于 0 会更快(无需将您比较的值加载到 CPU 中)
  • @Tom - 大多数 ISA 支持立即值,因此您与固定值的比较速度应该为零(当然也有例外)。
  • @Michael 在过去的 x86 时代(以及一般的 CISC),即时加载仍然比与零比较(通常使用类似 AND ax,ax / JNZ tgt 或类似的东西)慢。在过去的 RISC 中,仅在单独的 load 指令上支持立即值来进行比较,但至少在 MIPS 上,$0 始终加载值 0。
【解决方案3】:

听起来您应该阅读Intel 64 and IA-32 Architectures Optimization Reference Manual

在您使用的说明中查看“管道延迟”和“管道延迟”。可以说,您对 ints 所做的一切都需要大约 1 个时钟周期来执行(每秒 40 亿个)。从内存中读取数据可能需要 100-1000 次,具体取决于您正在处理的数据量。重要得多。

【讨论】:

    【解决方案4】:

    比较通常被实现为忽略结果的减法。 CPU 中的加法器将同时对所有位进行操作,因此这是一个恒定时间操作。

    然后,平等只是确定输出是否为 0。在 x86 上,作为比较结果设置了一些标志,并且通过 jz 或 jnz 完成分支(如果为零则跳转,如果不为零则跳转)。所以不,不会有真正的速度差异。

    其他平台(例如 ARM 和 IA64)的行为类似。

    【讨论】:

      【解决方案5】:

      指令本身将以相同的速度执行,正如其他答案所暗示的那样。

      您可能会遇到差异的地方是分支预测或缓存效果。这会因处理器和编译器而异,因此无法一概而论。如果您处于这会产生影响的水平,那么唯一知道的方法就是尝试并衡量。

      【讨论】:

      • 这是真的。处理器当前将假定不采用分支,即执行每个 if 语句主体,而没有进一步的提示。编译器可能会意识到 if 不太可能并以不同的方式构造它/放入分支提示。
      【解决方案6】:

      如果您想将此问题提出更一般的问题,则必须考虑 TRUE 和 FALSE 答案的合理分布,并且必须考虑任意字长,包括比寄存器更长的字长。

      在搜索算法中(排序可以被认为是搜索的扩展),使用“

      在任何一种情况下,它们都会进行 O(word length) 的位比较,但是,如果 word-length

      【讨论】:

        【解决方案7】:

        比较操作发生在微处理器时钟信号的上升沿(或下降沿)。然后下一个操作发生在下一个时钟周期。因此,就执行速度而言,对于当今市场上的几乎所有处理器而言,相等和不等式所花费的时间都相同。

        我说几乎是因为我记得读过一些处理器,这些处理器应该不是基于时钟,而是基于操作时间,所以如果比较操作确实比添加操作快,那么一组 n 比较所花费的时间少于 n 添加的时间。但我有 99% 的把握这只是一些研究项目,而不是商业产品 :)

        【讨论】:

        • 与现代 CPUS 相比,您说的是极其简单的处理器。在现代 CPU 中,指令经常被重新排序,同时执行,并且有几条指令同时退出(完成)。您对指令执行的物理顺序或指令之间的缺陷的任何假设都可能过于简单。在这个例子中,让 CPU 解码两条指令,将它们合二为一并在一个时钟内执行,这将是一个明显的潜在优化。
        • er *缺陷 -> 依赖项。另外,请参阅我的其他答案中的优化 PDF 以获取更多详细信息。
        • OP 和我一样特别提到了微处理器。如果从微处理器开始,那我就说处理器含糊不清。
        【解决方案8】:

        有一些小情况可能会产生一些影响。

        在 ARM 处理器上(对于 32 位/非拇指指令集架构 (ISA)),所有指令都是有条件的。有时,尽管有多个条件,但您可以摆脱具有单个分支(从头到尾)的内部循环。在少数情况下,具有逻辑比较 (TEQ) 的干扰很少的标志(影响负 (N) 和零 (Z),但不影响进位 (C) 或溢出 (V)),允许毛茸茸的代码避免分支指令(未拍摄)。

        相反,IIRC(我从未真正对其进行过编程,但在十多年前看过 C 编译器的输出)68000 具有仅用于寄存器 D4 的文字 EOR/XOR 指令。所以算术比较可能会更好(尽管您仍然可以忽略无关的标志 - 关键是指令集有点不规则)。

        正如之前的海报所提到的,大部分操作都与内存、磁盘、网络和 Web 服务延迟有关。

        【讨论】:

          【解决方案9】:

          每个人都假设的一个方面是他在谈论寄存器级指令。每个人都是对的,它基本上在 CPU 级别上没有实际意义。甚至更高级别的大多数高级操作都将不等式写成对等式的调用被否定。

          但是,即使在更高层次上,使用提问者的优化也可以双向发挥作用。也就是说,等式可以写成和不等式一样有效。

          此外,对于与汇编操作有关的人来说,CMP 和 SUB 之间的唯一区别是设置了哪些标志。它们通常在机器的相同部分执行,因为 CMP 必须返回表示相等、小于和大于的标志。

          【讨论】:

            【解决方案10】:

            进行这样的比较所需的时间通常是一个时钟周期。

            32 位处理器将同时处理所有 32 位; 64 位将一次执行 64 位。

            如果在管道中出现延迟或停顿,那将是因为操作数不可用并且必须获取。 这是开销最大的地方。但这会在适合处理器架构的块中完成,所以它仍然会作为 32 位或 64 位单元被拉入。

            【讨论】:

              猜你喜欢
              • 2015-01-05
              • 1970-01-01
              • 2010-11-28
              • 2013-12-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-11-02
              相关资源
              最近更新 更多