考虑以下循环:
unsigned long x = 0;
for(unsigned long i = 2314543142; i > 0; i-- )
x+=i;
std::cout << x << std::endl;
当我正常编译时,执行此循环大约需要6.5秒钟。但是当我使用-O3优化进行编译时,循环在10 ^ -6秒内执行。这怎么可能?编译器肯定不知道x的闭合表达式...
考虑以下循环:
unsigned long x = 0;
for(unsigned long i = 2314543142; i > 0; i-- )
x+=i;
std::cout << x << std::endl;
当我正常编译时,执行此循环大约需要6.5秒钟。但是当我使用-O3优化进行编译时,循环在10 ^ -6秒内执行。这怎么可能?编译器肯定不知道x的闭合表达式...
如果开启了优化编译,编译器就能在编译期间确定x的值,这并不需要你完全了解汇编语言。
我稍微修改了你的代码,以便使用在线工具Compiler Explorer,将std::cout << x << std::endl
改为extern unsigned long foo;
和foo = x;
。虽然不是必须的,但可以使输出更加干净。
使用-O2编译:
test():
movabs rax, 2678554979246887653
mov QWORD PTR foo[rip], rax
ret
使用-O0编译:
test():
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], 0
mov DWORD PTR [rbp-16], -1980424154
mov DWORD PTR [rbp-12], 0
jmp .L2
.L3:
mov rax, QWORD PTR [rbp-16]
add QWORD PTR [rbp-8], rax
sub QWORD PTR [rbp-16], 1
.L2:
cmp QWORD PTR [rbp-16], 0
setne al
test al, al
jne .L3
mov rax, QWORD PTR [rbp-8]
mov QWORD PTR foo[rip], rax
leave
ret
test():
.L2:
jmp .L2
:-)
extern unsigned foo
而不是extern unsigned long foo
。更新后的答案显示了正确的输出值。 - simon
i
是无符号的。i >= 0
将总是为真。你在这里有未定义的行为。我很惊讶在默认优化级别下循环竟然结束了。 - user23571121
到n
的所有整数之和在数学上等于n*(n+1)/2
(即可以使用加法、乘法和除法计算,而不是n
次加法)。许多编译器优化器的一个特点是它们识别可以更简单地计算结果的操作序列(例如,在这种情况下是一个闭合形式),并且在编译时进行计算或发出简单的代码以在运行时执行。 - Peter