x> = 0比x> -1更有效吗?

ger*_*ddp 6 c++ optimization micro-optimization

在C++中使用int进行x >= 0比较比效率更高x > -1

aki*_*ira 19

简短的回答:没有.

更长的答案提供一些教育见解:它完全取决于你的编译器,尽管我敢打赌,每个理智的编译器为2个表达式创建相同的代码.

示例代码:

int func_ge0(int a) {
    return a >= 0;
}   

int func_gtm1(int a) {
    return a > -1; 
}
Run Code Online (Sandbox Code Playgroud)

然后编译并比较生成的汇编程序代码:

   % gcc -S -O2 -fomit-frame-pointer foo.cc

得出这个:

_Z8func_ge0i:
.LFB0:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    movl    4(%esp), %eax
    notl    %eax
    shrl    $31, %eax
    ret
    .cfi_endproc

_Z9func_gtm1i:
.LFB1:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    movl    4(%esp), %eax
    notl    %eax
    shrl    $31, %eax
    ret
    .cfi_endproc

(编译器:g ++ - 4.4)

结论:如果有疑问,请不要试图超越编译器,专注于算法和数据结构,基准测试和配置真正的瓶颈:检查编译器的输出.

  • 这个特殊的程序集实际上非常聪明:它返回最高位的值,即"符号位". (10认同)

lit*_*adv 7

您可以查看生成的汇编代码,这可能因架构而异,但我敢打赌,两者的结果代码都需要完全相同的周期.

并且,正如评论中所提到的 - 更好地编写最易于理解的内容,在有实际测量瓶颈时进行优化,您可以使用分析器识别这些瓶颈.

BTW:不管正确提到的,x>-1如果可能引起的问题xunsigned.它可能被隐含地投入signed(虽然你应该得到一个警告),这会产生不正确的结果.


Che*_*Alf 6

我最后一次回答这个问题时,我只是写了"措施",并填写了句号直到SO接受它.

该回答在几分钟内被贬低了3次,并被SO主持人删除(以及该问题的至少一个其他答案).

尽管如此,除了测量之外别无选择.

所以这是唯一可能的答案.

并且为了继续详细说明答案不仅仅是低估和删除,你需要记住,你所测量的只是:一组测量并不一定告诉你一般的东西,但只是一个特定的结果.当然,提到这些显而易见的事情可能听起来很光顾.所以,好吧,让它成为它:只是衡量.

或者,我是否应该提一下大多数处理器都有一个特殊的指令来比较零,但是那不能让你得到关于代码片段性能的任何结论?

好吧,我想我就在那里.记住:衡量.并且不要过早优化!



编辑:修正案中@MooingDuck在评论中提到的要点.

问题:

做在C++的比较用intx >= 0比更有效x > -1

这个问题出了什么问题

Donald Knuth,经典三卷作品"计算机编程艺术"的作者曾写过[1],

"我们应该忘记小的效率,大约97%的时间说:过早的优化是所有邪恶的根源"

如何有效的 x >= 0进行比较,x > -1是最常见无关.也就是说,重点关注的可能是错误的.

它表达你想说的内容有多清楚,更为重要.您维护此代码的时间和时间通常比程序的执行时间重要得多.关注代码与其他程序员的沟通情况,即注重清晰度.

为什么问题的焦点是错误的

清晰度会影响正确性.如果不需要正确的话,任何代码都可以任意快速地制作.因此,正确性是最重要的,并且意味着清晰度非常重要 - 比剃须纳秒执行时间更重要......

这两个表达式等同于wrt.清晰度和wrt.他们正确的机会.

如果x是有符号整数,则x >= 0表示完全相同x > -1.但是,如果x是无符号整数,例如类型unsigned,则x > -1意味着x > static_cast<unsigned>(-1)(通过隐式促销),这反过来意味着x > std::numeric_limits<unsigned>::max().这可能不是程序员想表达的意思!

重点是错误的另一个原因(它在微观效率上,而应该在清晰度上)是对效率的主要影响通常不是来自单个操作的时间(除了在某些情况下来自动态分配和更慢)磁盘和网络操作),但从算法效率.例如,写...

string s = "";
for( int i = 0;  i < n;  ++i ) { s = s + "-"; }
Run Code Online (Sandbox Code Playgroud)

是非常低效的,因为它使用的时间与n,O(n 2),二次时间的平方成正比.

但是写作......

string s = "";
for( int i = 0;  i < n;  ++i ) { s += "-"; }
Run Code Online (Sandbox Code Playgroud)

缩短与n,O(n),线性时间成比例的时间.

随着对个人操作时间的关注,人们现在可能会想到写作'-'而非"-"如此愚蠢的细节.相反,在关注清晰度的情况下,人们会专注于使代码比循环更清晰.例如,通过使用适当的string构造函数:

string s( n, '-' );
Run Code Online (Sandbox Code Playgroud)

哇!

最后,第三个不让小东西流汗的原因是,通常它只是代码的一小部分,它对执行时间的贡献不成比例.通过分析代码来识别那部分(或部分)并不容易.需要进行测量,这种"在何处花费时间"测量称为剖析.

如何找出问题的答案

二三十年前,只需查看生成的机器代码,就可以合理地了解单个操作的效率.

例如,您可以通过在调试器中运行程序来查看机器代码,或者使用approiate选项要求编译器生成汇编语言列表.关于g ++的注意事项:该选项-masm=intel很方便告诉编译器不要生成不可编辑的AT&T语法汇编,而是生成Intel语法汇编.例如,Microsoft的汇编程序使用扩展的Intel语法.

今天,计算机的处理器更加智能.它可以不按顺序执行指令,甚至在"当前"执行点需要它们之前执行.编译器可能能够预测(通过结合从测量中收集的有效知识),但人类几乎没有机会.

因此,普通程序员的唯一办法是衡量.

测量,测量,测量!

总的来说,这包括做一件需要测量的事情,数十亿次,然后除以万亿次.

否则启动时间和取下时间将占主导地位,结果将是垃圾.

当然,如果生成的机器代码相同,那么测量不会告诉您有关相对差异的任何有用信息.然后,它只能指示测量误差有多大.因为你知道那应该是零差异.

为什么测量是正确的方法

让我们说SO答案中的理论考虑表明x >= -1会慢于x > 0.

编译器可以通过为此生成可怕的代码来击败任何这样的理论考虑x > 0,可能是由于它(不幸的是!)识别的上下文"优化"机会.

计算机的处理器同样可以使预测变得混乱.

所以无论如何你必须要衡量.

这意味着理论上的考虑并没有告诉你任何有用的东西:无论如何你都会做同样的事情,即测量.

为什么这个详细的答案,虽然显然有帮助,恕我直言,真的没有

我个人更喜欢单词"measure"作为答案.

因为这就是它归结为.

读者不仅可以自己弄清楚任何其他东西,而且还必须弄清楚无论如何都要详细说明 - 所以,试着在这里描述它真的只是措辞.

参考文献:

[1] Knuth,唐纳德.结构化编程,参见陈述,ACM Journal Computing Surveys,Vol 6,No.4,1974年12月.p.268.

  • 不幸的是,仅仅因为答案是准确的并不意味着它是一个很好的答案. (2认同)