2014-12-05 74 views
3

我試圖事情constexpr爲什麼鏗鏘不會用斐波那契的constexpr版本計算斐波納契(500)?

#include <iostream> 

constexpr long long fibonacci(const int x) 
{ 
    return x <= 1 ? 1 : fibonacci(x - 1) + fibonacci(x - 2); 
} 

int main() 
{ 
    const long long lol = fibonacci(500); 
    std::cout << lol << std::endl; 
} 

所以我想lol在編譯時進行計算:

[email protected] 
» g++ -std=c++14 -g src/test.cc -o test.out 
[email protected] 
» ./test.out 
4859788740867454402 

它的工作真的很好用g++。在編譯時,它甚至會做一些記憶,優化這個蹩腳的fibonnaci函數,然後立即計算fibonacci(500)

然後我試着用clang++

[email protected] 
» clang++ -std=c++1y -g src/test.cc -o test.out 
[email protected] 
» ./test.out 
... very long 

lol不受clang++(由gdb證明),在編譯時計算。 爲什麼?

+3

此外,克++正在計算的東西,但不是第500 Fibonacci數。它很快溢出。即使30日也不會長久。 – 2014-12-05 16:20:33

+0

根據[here](http://clang.llvm.org/docs/UsersManual.html#cmdoption-fconstexpr-depth),constexpr遞歸調用的默認深度是512.所以我猜這裏沒有問題它。正如@Cornstalks – streppel 2014-12-05 16:20:35

+2

所提到的那樣,我認爲機會是一個整數溢出。此外,clang/gcc可能會檢測到一些溢出,並且由於有符號整數溢出是未定義的行爲,它們可能會產生不同的結果。 (考慮到第500個Fibonacci數爲[139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125](http://www.wolframalpha.com/input/?i=fibonacci+number+500)) – Cornstalks 2014-12-05 16:22:01

回答

8

它擊中鐺的最大遞歸深度。您可以強制lol將通過使constexpr,即在編譯時評價:

constexpr long long lol = fibonacci(500); 

這樣做,並與clang++ -std=c++11 t.cpp編譯給人的錯誤:

t.cpp:10:25: error: constexpr variable 'lol' must be initialized by a constant 
     expression 
    constexpr long long lol = fib(500); 
         ^ ~~~~~~~~ 
t.cpp:4:1: note: constexpr evaluation hit maximum step limit; possible infinite 
     loop? 
{ 
^ 
t.cpp:5:38: note: in call to 'fib(4)' 
    return x <= 1 ? 1 : fib(x - 1) + fib(x - 2); 
            ^
t.cpp:5:25: note: in call to 'fib(6)' 
    return x <= 1 ? 1 : fib(x - 1) + fib(x - 2); 
         ^
t.cpp:5:38: note: in call to 'fib(7)' 
    return x <= 1 ? 1 : fib(x - 1) + fib(x - 2); 
            ^
t.cpp:5:25: note: in call to 'fib(9)' 
    return x <= 1 ? 1 : fib(x - 1) + fib(x - 2); 
         ^
t.cpp:5:25: note: in call to 'fib(10)' 
t.cpp:5:25: note: (skipping 480 calls in backtrace; use 
     -fconstexpr-backtrace-limit=0 to see all) 
t.cpp:5:25: note: in call to 'fib(496)' 
t.cpp:5:25: note: in call to 'fib(497)' 
t.cpp:5:25: note: in call to 'fib(498)' 
t.cpp:5:25: note: in call to 'fib(499)' 
t.cpp:10:31: note: in call to 'fib(500)' 
    constexpr long long lol = fib(500); 
          ^
1 error generated. 

鏘不能(默認編譯器標誌;儘管我仍然無法在編譯時使用-fconstexpr-depth=1000000000(即10億)進行編譯),因此在編譯時評估fibonacci(500),所以它會在運行時使用您發佈的代碼進行編譯。正如@Streppel鏈接到的那樣,您可以使用-fconstexpr-depth=N編譯器標誌來增加常量表達式的最大遞歸深度。

然而,第500斐波那契數是巨大的*,所以這肯定會溢出,這是有符號整數未定義行爲(所以所有的賭注都關閉,真的)。 (But you can do it if you use template metaprogramming

* as in 105 digits huge:139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125