为什么不同(!=,<>)快于等于(=,==)?

时间:2009-07-14 10:15:06

标签: performance delphi optimization

我在SO <>语句中看到“=!=”或“==”快if()更快的评论。

我想知道为什么会这样。你能在asm中展示一个例子吗?

谢谢! :)

编辑:

Source

这就是他所做的。

  function Check(var MemoryData:Array of byte;MemorySignature:Array of byte;Position:integer):boolean;
   var i:byte;
   begin
    Result := True; //moved at top. Your function always returned 'True'. This is what you wanted?
    for i := 0 to Length(MemorySignature) - 1 do //are you sure??? Perhaps you want High(MemorySignature) here... 
    begin
{!}  if MemorySignature[i] <> $FF then //speedup - '<>' evaluates faster than '='
     begin
      Result:=memorydata[i + position] <> MemorySignature[i]; //speedup.
      if not Result then 
        Break; //added this! - speedup. We already know the result. So, no need to scan till end.
     end;
    end;
   end;

12 个答案:

答案 0 :(得分:19)

我声称这可能是错误的,除非在非常特殊的情况下。编译器可以毫不费力地将一个重构为另一个(仅通过切换ifelse个案例。)

答案 1 :(得分:6)

它可能与CPU上的分支预测有关。静态分支预测将预测不会采用分支并获取下一条指令。但是,几乎没有人再使用它了。除此之外,我会说这是公牛,因为比较应该是相同的。

答案 2 :(得分:6)

我认为你的previous question中有一些关于你试图实施的算法是什么的混淆,因此声称“加速”声称要做什么。

这是Delphi 2007的一些反汇编。优化。 (注意,优化关闭稍微改变了代码,但不是以相关的方式。

Unit70.pas.31: for I := 0 to 100 do
004552B5 33C0             xor eax,eax
Unit70.pas.33: if i = j then
004552B7 3B02             cmp eax,[edx]
004552B9 7506             jnz $004552c1
Unit70.pas.34: k := k+1;
004552BB FF05D0DC4500     inc dword ptr [$0045dcd0]
Unit70.pas.35: if i <> j then
004552C1 3B02             cmp eax,[edx]
004552C3 7406             jz $004552cb
Unit70.pas.36: l := l + 1;
004552C5 FF05D4DC4500     inc dword ptr [$0045dcd4]
Unit70.pas.37: end;
004552CB 40               inc eax
Unit70.pas.31: for I := 0 to 100 do
004552CC 83F865           cmp eax,$65
004552CF 75E6             jnz $004552b7
Unit70.pas.38: end;
004552D1 C3               ret 

如您所见,这两种情况的唯一区别是jz与jnz指令。这些将以相同的速度运行。更可能影响事情的是分支的使用频率,以及整个循环是否适合缓存。

答案 3 :(得分:5)

对于.Net语言

如果从string.op_Equalitystring.op_Inequality方法查看IL,您会看到两个内部调用string.Equals。

但是op_Inequality反转了结果。这是两个IL声明。

我会说它们的性能是相同的,对于==语句可能有一个小的(非常小的,非常小的)更好的性能。但我相信优化器&amp; JIT编译器将删除它。

答案 4 :(得分:4)

虽然自发;代码中的大多数其他内容会影响性能,而不是==和!=(或=和&lt;&gt;取决于语言)之间的选择。

当我在C#中进行1000000次迭代比较字符串测试时(包含字母表,a-z,其中一个字母反转最后两个字母),差异在0到1毫秒之间。

之前已经说过:编写可读性代码;当确定它会产生影响时,将其转换为性能更高的代码

编辑:用字节数组重复相同的测试;一样;性能差异是可以忽略的。

答案 5 :(得分:4)

这也可能是对实验误解的结果。

大多数编译器/优化器都假定默认采用分支。如果反转运算符和if-then-else顺序,并且现在采用的分支是ELSE子句,则可能会在高度计算代码中导致额外的速度效应(*)

(*)显然你需要为此做很多操作。但是对于例如最紧密的环路来说,它可能很重要。编解码器或图像分析/机器视觉,您可以在其中传输50MByte / s的数据。 ....然后我甚至只是为了真正重复使用的代码而屈服于这个级别。对于普通的商业代码,这是不值得的。

答案 6 :(得分:2)

我声称这是错误的完全停止。平等的测试总是与不平等的测试相同。使用字符串(或复杂的结构测试),您总是会在完全相同的点上中断。在达到这个突破点之前,平等的答案是未知的。

答案 7 :(得分:1)

如果你能提供一个清楚显示差异的小例子,那么我确信Stack Overflow社区可以解释原因。但是,我认为你可能难以构建一个明确的例子。我不认为在任何合理的范围内都会有明显的性能差异。

答案 8 :(得分:1)

我强烈怀疑速度有什么不同。例如,对于整数类型,您将获得CMP指令和JZ(如果为零则跳转)或JNZ(如果不为零则跳转),具体取决于您使用的是=还是≠。这里没有速度差异,我希望在更高的水平上保持正确。

答案 9 :(得分:1)

ASM指令的这个列表(假设它在x86上)可能会有所帮助:

(免责声明,我只有非常基本的编写汇编程序的经验,所以我可能会脱离标记)

然而,它显然完全取决于Delphi编译器生成的汇编指令。没有看到输出,那就是猜测。我将保留我的唐纳德克努特的报价,因为关心这类事情,除了一系列应用程序(游戏,移动设备,高性能服务器应用程序,安全关键软件,导弹发射器等)就是你的事情。我认为最后担心。

  

“我们应该忘记小事   效率,约占97%   时间:过早优化是   万恶之源。“

如果您正在写其中一个或类似的,那么显然您会关心,但您没有指定它。

答案 10 :(得分:1)

它可能是或者它不可能,这是问题:-) 问题在于这取决于您使用的编程语言。 由于所有语句最终都将作为CPU的指令结束,因此使用最少量指令来实现结果的语句将是最快的。

例如,如果您说位x等于位y,则可以使用使用两个位作为输入执行XOR的指令,如果结果为0,则它​​不相同。那么你怎么知道结果不是0呢?如果你说输入a大于0,则使用返回true的指令。

所以这已经是你用来做的2条指令,但由于大多数CPU都有一个指令在一个周期内进行比较,这是一个不好的例子。

我所提出的观点仍然相同,如果不提供编程语言和CPU架构,就无法做出这种普遍的陈述。

答案 11 :(得分:1)

只是猜测,但鉴于你想保留逻辑,你不能只是替换

if A = B then

if A <> B then

为了保存逻辑,原始代码必须类似于

if not (A = B) then

if A <> B then
else

这可能比对不平等的测试要慢一点。