使用"大于或等于"或仅使用"大于"。

13

我还记得从C语言时代开始,我们被鼓励使用

i > -1

取代

i >= 0

因为性能问题。

在C# .NET世界中是否仍然适用?在当前编译器下使用它们之一会有什么性能影响?也就是说,编译器是否足够聪明,可以为您进行优化?

(另外,请尝试在 Stack Overflow 的问题字段中输入“使用>=还是>”并查看发生了什么。)

8个回答

47

没有与比较运算符相关的性能问题。任何好的编译器都会优化这件微不足道的事情。

我不确定你从哪里得到使用"i > -1"而不是"i >= 0"的建议。在x86架构上,使用哪种方式都没有区别:任何一种情况都需要精确的两个指令...一个用于比较和一个用于跳转:

 ;; if (i > -1) {
 cmp eax, -1
 jle else
then:
 ...
else:

 ;; if (i >= 0) {
 cmp eax, 0
 jl else
then:
 ...
else:

根据我所知,对于大多数RISC架构,“i>=0”可能会更快,因为通常有一个专用的零寄存器,而“i>-1”可能需要加载一个常量。例如,MIPS只有一个<指令(没有<=)。以下是这两个结构在MIPS汇编语言中的(天真地!)表示方式:

 // if (i >= 0) {   (assuming i is in register %t0)

 stl $t1, $0, $t0     // in C: t1 = (0 < t0)
 beq $t1, $0, else    // jump if t1 == 0, that is if t0 >= 0
 nop
then:
 ...
else:

// if (i > -1) {    (assuming i is in register %t0)

 addi $t2, $0, -1      // in C: t2 = -1
 stl $t1, $t2, $t0      // in C: t1 = (t2 < t0) = (-1 < t0)
 bne $t1, $0, else     // jump if t1 != 0, that is if t0 > -1
 nop
then:
 ...
else:

因此,在天真的普遍情况下,在MIPS上执行"i >= 0"实际上会比执行"i < size"快一个指令。当然,RISC代码非常可优化,编译器很可能会将任一这些指令序列改变到几乎无法识别的程度 :-)

所以...简短的答案是不不不,没有区别。


5
“(不不不,没有区别)= !(!(!(!区别)))= !(!区别)= 区别” ;) - M.kazem Akhgary
1
@M.kazemAkhgary,很难反驳这一点。现在我有点想加第五个“不” :-P - Dan Lenski

12

除了任何体面的编译器都会做正确的事情,以及在现代架构中>>=比较没有速度差异之外,更重要的是这是一种“微优化”,在绝大多数情况下不会影响运行时性能。

在比较方面,通常无论你如何写都不会影响可读性,但有时选择一个边界比另一个更清晰明了,例如:

if (length >= str.size())

对比

if (length > str.size() - 1)

我不知道你怎么想,但我每天都会选择选项1。:-) 在不会明显影响性能的情况下,可读性更好的选项应该获胜。


1
没错。“过早优化是万恶之源。”(唐纳德·克努斯) - Dan Lenski
请注意,如果str.size()返回的是无符号数,则上述两个语句不等价。特别地,如果str.size()为零,则后者永远不会评估为真。我有时会使用这样的代码,尽管我通常会添加一个显式的类型转换为无符号数:如果大小为“short”,“if(length>(unsigned short)(str.size-1))”将有助于明确代码期望包装行为。 - supercat

9
这里有一个非常相似的问题(无意批评-正如您所说,搜索符号是棘手的):“在for循环中应该使用<还是<= (是的,我碰巧很容易找到它,因为我的答案得到了很多赞同...)
基本上,做最易读的事情。如果某天有人正确猜测,改变最易读的形式将解决性能问题(没有分析器的帮助),那么我就会停止谈论性能 :)

5

现在你不需要这样做了。是的,编译器变得更加智能化,这两个表达式没有性能差异。


我仍然无法相信曾经存在这样的环境,那里会有区别。有人能告诉我一个现存的架构,在其中一个比另一个需要更少的周期吗? - Dan Lenski
1
听起来像是一个编程界的传奇故事。 - matt b

3

我还记得在C语言时代,我们被鼓励使用“>=”来提高性能。

你确定吗?我从70年代初开始就接触计算机(是的,在我父亲的膝盖上...),我从来没有见过不能像“>”一样快速处理“>=”的CPU。(在IBM360中,“BH”代表“分支高”,“BNL”代表“分支不低”)。


我同意,詹姆斯。我能想到的是MIPS,它只有小于号。因此编译器通常会将"a <= b"重新排列为"not (b < a)"。唯一不起作用的情况是其中一个是非零常数... - Dan Lenski
我认为这是一个普遍的谬论。我从同事那里听到过,甚至在过去几年中在互联网上也看到过。即使没有编译器优化差异,为了节省一个CPU指令而付出如此巨大的努力是一种巨大的浪费。 - Mnebuerquo
就像你所说的那样 - 这可能是我被误导了的事情 - 谢谢。 - Guy

3

这可能对于一些不太正规的脚本语言是正确的,因为它们将“>=”拆分为两个比较操作,但是如果有人鼓励你在C中使用这种方式……那么你应该尽力忘记他们告诉你的一切。


2
这让我想起了建议使用++i代替i++(预增量与后增量)的推荐,因为它据说比后者快一条指令。(我忘记了我最初在哪里读到这个建议,但可能是在C/C++用户杂志或Dr. Dobb's Journal,但我似乎找不到网络参考。)
我严重怀疑>或>=是快还是慢;相反,请编写清晰易懂的代码。
顺便说一句,尽管原因现在可能已经过时了,但我更喜欢使用预增量(++i)运算符。

1
在C++中,有理由更喜欢一种增量而不是另一种 - 我相信推荐使用前增量。 - Jonathan Leffler

-1

对于大于零的情况,必须进行两项检查。它会检查负数位是否关闭,并检查零位是否关闭。

对于大于或等于零的情况,只需检查负数位是否关闭,因为我们不关心零位是否开启或关闭。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接