-5

我想知道这些片段中哪一个更快。

我通常使用这个表达式:

if(x <= y)
    break;

但是使用它有优势吗?

if(!(x > y))
    break;

这是我的推理。我认为第一个陈述实际上是这样的:

if(x == y)
    break;
if(x < y)
    break;

但我认为第二个说法只是这样:

if(!(x > y))
     break;

这使我相信第二个语句更快。这是正确的吗?

4

6 回答 6

8

编译使用gcc -O3 -march=native -m64 -fomit-frame-pointer -S

int f(int x, int y) {
    if (x <= y) return 1;
    return 0;
}

f:
    xorl    %eax, %eax
    cmpl    %edx, %ecx
    setle   %al
    ret

int f(int x, int y) {
    if (!(x > y)) return 1;
    return 0;
}

f:
    xorl    %eax, %eax
    cmpl    %edx, %ecx
    setle   %al
    ret

也就是说,对于整数,它们完全相等——事实上,编译器将第二个示例优化为第一个示例,因为它更快,而不是更慢

于 2013-07-28T13:55:25.340 回答
4

编译器不太可能生成与另一个不同的东西。几乎所有现代处理器都有greater or equalless or equal比较/分支操作,因此没有理由进行更复杂的比较。

该声明

 if(x == y) 
      if (x < y) 
         break;

没有任何意义。要么x == y是真的,在这种情况下x < y是不正确的。或者x == y是假的,如果你根本不输入第二个。

显然,如果xy是一个类,那么operator<=可以写成:

operator<=(const A& x, const A& y)
{
    if (x == y) return true;
    return x < y; 
}

但这很愚蠢,因为它也可以写成:

operator<=(const A& x, const A& y)
{
    return !(x > y); 
}
于 2013-07-28T13:49:26.023 回答
1

就 int (或 short 或 long long 或其他)而言,只需使用x <= y,编译器应该对其进行优化。例如在 x86-64 上:

    cmpq %rax, %rcx
    jg false
#This is code to execute if (x <= y).
# Code
# .......
false:
    #This is code to execute once the
    # if statement is done or the condition
    # resulted in a falsy value.

如果你有一个 if-else 语句,有两个跳转指令:第一个是如果条件产生一个假值,第二个是在代码块的末尾,当条件产生一个真值时(所以它可以跳过在用于 else 块的代码上)。

请注意,我使用了 jg(如果大于则跳转)指令。x86 和 x86-64 都有一个 jnle (如果不小于或等于则跳转)指令,但它做同样的事情(毕竟,如果 x 不小于或等于 y,那么逻辑上 x 必须大于比 y),但从在 ASM 中工作的角度来看,反转条件更有意义。如果条件没有被反转,你会向前跳来执行 if 语句的代码,然后向后跳来恢复程序的主要流程。为什么在两次跳跃中完成一次可以完成的事情?

顺便说一句,我不是 ASM 专家。但是,如果您稍微使用它,它可以帮助您避免提出此类问题,因为编译器应该优化您的(x <= y)条件以进行!(x > y)编码,正如我所展示的那样。无需尝试再次猜测您的编译器。专注于您可以进行的常规优化以帮助编译器优化您的代码,例如消除不需要执行的条件,而不是它已经知道如何做的小东西。

于 2013-07-28T14:17:20.187 回答
1

假设 x & y 是内置类型,

这是我的推理。我认为第一个陈述实际上是这样的:

if(x == y)
    if(x < y)
        break;

这个不对。CPU 可以进行<=操作。不要过度优化;)

于 2013-07-28T13:46:24.667 回答
1

您可以期望任何足够先进的编译器自动将这些等效语句优化为目标架构上最快的语句,因此在实践中它们的行为相同。

但是,当这些片段按字面意思解释时,在 x86 架构上,第一个操作将是单个操作,因为 x86 CPU 指令集具有用于少时跳转和少时或等于时跳转的指令。

于 2013-07-28T13:48:08.420 回答
0

您应该使用的原因有 2 个<=

  1. CPU 可以<=对原语进行操作。

  2. 如果这些类有一个重载<=的运算符,那么可以安全地假设它已经过优化,可以做得比它更好if(!(x > y))或至少等于它。因此,如果它存在,请使用它。有人努力实施它是有原因的。

于 2013-07-28T13:50:00.327 回答