在C++中哪个更快:i<=N还是i<N+1?

3

以下两个for循环都将被执行N+1次:

for(int i = 0; i <= N; ++i);
for(int i = 0; i < N + 1; ++i);

在这两个表达式中,哪一个更快计算(i <= N or i < N + 1)?我知道有一个类似的流行问题(Is < faster than <=?),但是我认为这个问题不同,因为我们在将1添加到一个可能不是常量的变量,然后将其与i进行比较,而不是与一个常量值进行比较。


9
如果它们组装成同样的部件,我并不会感到惊讶。 - tkausl
编译器比你想象的要聪明。如果你想知道,可以用自己的计时器或使用分析工具来尝试。无论如何,你的 N + 1 不会被计算 N 次,所以我不明白这样做的意义... - RaphaMex
1
如果N不是一个常量值,那么这两个表达式并不完全相同;N + 1可能会溢出。 - Keith Thompson
3
任何一个循环都可以被完全优化掉。循环体没有任何操作,而且变量“i”是循环内部的本地变量,因此其值无关紧要。编译器可能比您预期的更聪明或更愚蠢。C++语言并未涉及两个循环的相对性能。你的问题实际上是关于代码在你使用的实现上的性能,唯一的解决方法就是进行测量。 - Keith Thompson
@JonathonReinhart 我明确解释了为什么它不是。 - DimK
显示剩余4条评论
1个回答

5

首先,如果 N 是常量,则编译器会在编译时计算 N+1,并为两个选项生成相同数量的指令。关于变量与常量比较的情况,在此问答中有很好的解释。

N 是一个只在运行时可用的变量时,一个运行在高级优化水平的编译器也可能为两种比较生成相同的代码。

我使用 gcc-O3 优化级别下进行了实验,给它这两个代码片段:

scanf("%d%d", &j, &k);
if (j < k+1) {
    printf("hello\n");
}

并且

scanf("%d%d", &j, &k);
if (j <= k) {
    printf("hello\n");
}

我使用了scanf来防止编译器完全优化表达式。

两种情况下生成的汇编代码是相同的:

movl    -8(%rbp), %eax
cmpl    -4(%rbp), %eax
jg      LBB0_2

在IT技术中,当j大于k时,会将jk进行比较,并跳过对printf的调用(优化器已将其替换为对puts的调用)。


2
干得好!永远不要假设编译器会做什么。只需检查它。对于N=16和N=17,它可能会有不同的编译方式,而你却不知道为什么。是的,这种情况曾经发生在我身上。 - RaphaMex
可能还需要针对N是类类型对象(支持相应操作)的情况进行注释。 - Peter

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