[英]How can a const expr be evaluated so fast
我一直在嘗試在編譯時計算的 const 表達式。 但是我玩了一個在編譯時執行時看起來非常快的示例。
#include<iostream>
constexpr long int fib(int n) {
return (n <= 1)? n : fib(n-1) + fib(n-2);
}
int main () {
long int res = fib(45);
std::cout << res;
return 0;
}
當我運行此代碼時,大約需要 7 秒才能運行。 到現在為止還挺好。 但是當我將long int res = fib(45)
更改為const long int res = fib(45)
它甚至不需要一秒鍾。 據我了解,它是在編譯時評估的。 但是編譯大約需要0.3秒
編譯器怎么能這么快地評估它,但在運行時卻需要更多的時間? 我正在使用 gcc 5.4.0。
編譯器緩存較小的值,不需要像運行時版本那樣重新計算。
(優化器非常好,會生成大量代碼,包括我無法理解的特殊情況的詭計;天真的 2^45 遞歸需要幾個小時。)
如果您還存儲以前的值:
int cache[100] = {1, 1};
long int fib(int n) {
int res = cache[n];
return res ? res : (cache[n] = fib(n-1) + fib(n-2));
}
運行時版本比編譯器快得多。
您可能會發現 5.4 的功能並沒有完全消除很有趣,為此您至少需要 6.1。
我不認為有任何緩存發生。 我確信優化器足夠聰明,可以證明fib(n - 2)
和fib(n-1)
並完全避免第二次調用。 這是 GCC 5.4 輸出(從 Godbolt 獲得),沒有constexpr
和 -O2:
fib(long):
cmp rdi, 1
push r12
mov r12, rdi
push rbp
push rbx
jle .L4
mov rbx, rdi
xor ebp, ebp
.L3:
lea rdi, [rbx-1]
sub rbx, 2
call fib(long)
add rbp, rax
cmp rbx, 1
jg .L3
and r12d, 1
.L2:
lea rax, [r12+rbp]
pop rbx
pop rbp
pop r12
ret
.L4:
xor ebp, ebp
jmp .L2
我不得不承認我不理解 -O3 的輸出 - 生成的代碼非常復雜,有很多內存訪問和指針算法,很可能有一些緩存(記憶)使用這些設置完成。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.