2014-12-05 76 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