我想使用大整数值确定序列中的第n个Fibonacci项

时间:2014-02-07 19:07:33

标签: c++ algorithm math fibonacci

下面的代码能够使用数据类型unsigned long long确定直到70点的正确序列。我知道序列会变大,因此我修改了10,000个结果。我想使用最佳数据类型确定10,000的第n个术语,或者改进算法来计算第n个术语。

#define MOD %10000

unsigned long long calc(long nth) {
    return (pow( 1 + sqrt(5), nth ) - pow( 1 - sqrt(5), nth )) / (pow(2.0, nth)*(sqrt(5)));
}

int main() {
    long t, nth;
    for (std::cin>>t;  t-- && std::cin>>nth; ) {
        std::cout<<calc(nth-2)MOD<<" "<<calc(nth-1)MOD<<" "<<calc(nth)MOD<<std::endl;
    }   
    return 0;
}

2 个答案:

答案 0 :(得分:11)

由于sqrn(5)的浮点错误,您的算法无法为大N计算正确的结果。

为了加快算法速度,您可以使用快速加倍的Fibonacci:

   F(2k) = F(k)[2F(k+1) - F(k)]
   F(2k+1) = F(k+1)^2 + F(k)^2

应用模数算术,最后最快的算法是:

   F(2k) = F(k)[2F(k+1) - F(k)] % 10000
   F(2k+1) = (F(k+1)^2 + F(k)^2) % 10000

使用这种方法,您的函数永远不会超过10000,因此int类型就足够了。

编辑:好的,我在星期五晚上有空闲时间(我猜不是一件好事)并实施了算法。我实现了两个版本,第一个是 O (1)内存, O (lg n )时间复杂度,第二个是使用缓存,内存和 O (lg n )的最坏情况运行时,但最佳情况运行时为 O (1)。

#include <iostream>
#include <unordered_map>

using namespace std;

const int P = 10000;

/* Fast Fibonacci with O(1) memory and O(lg n) time complexity. No cache. */

int fib_uncached (int n)
{
    /* find MSB position */
    int msb_position = 31;
    while (!((1 << (msb_position-1) & n)) && msb_position >= 0)
        msb_position--;

    int a=0, b=1; 

    for (int i=msb_position; i>=0;i--)
    {       
        int d = (a%P) * ((b%P)*2 - (a%P) + P),
            e = (a%P) * (a%P) + (b%P)*(b%P);
        a=d%P;
        b=e%P;

        if (((n >> i) & 1) != 0)
        {
            int c = (a + b) % P;
            a = b;
            b = c;
        }
    }
    return a;
}  

/* Fast Fibonacci using cache */
int fib (int n)
{
    static std::unordered_map<int,int> cache;

    if (cache.find(n) == cache.end()) 
    {
        int f;
        if (n==0)
            f = 0;
        else if (n < 3)
            f = 1;
        else if (n % 2 == 0)
        {
            int k = n/2;
            f = (fib(k) * (2*fib(k+1) - fib(k))) % P;
        } 
        else
        {
            int k = (n-1)/2;
            f = (fib(k+1)*fib(k+1)+ fib(k) * fib(k)) % P;
        }
        if (f<0)
            f += P;

        cache[n] = f;
    }
    return cache.at(n);
}

int main ()
{
    int i ;
    cin >> i;
    cout << i << " : " << fib(i) << endl;
return 0;
}

无缓存实现的参考:https://www.nayuki.io/page/fast-fibonacci-algorithms

答案 1 :(得分:0)

连续计算术语,在每一步中取mod。由于每个术语仅取决于前两个术语,因此您的计算空间只是一个3元素阵列。

#include <iostream>
using namespace std;

typedef unsigned long long numtype;

const numtype MOD = 10000;

// Assume n is 1-based

numtype fib(int n)
{
  numtype seq[3] = {1,1,2};
  if( --n < 3 ) return seq[n]; // make n 0-based
  for( int i=3 ; i<=n ; ++i )
  {
    seq[i%3] = (seq[(i-1)%3] + seq[(i-2)%3]) % MOD;
    cout << seq[i%3] << ' '; // comment out for large n
  }
  return seq[n%3];
}

int main()
{
//numtype answer = fib(10000000); // 6875
  numtype answer = fib(70); // 9135
  cout << endl;
  cout << "answer = " << answer << endl;
}

输出:

  

3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 946 7711 8657 6368 5025 1393 6418 7811 4229 2040 6269 8309 4578 2887 7465 352 7817 8169 5986 4155 141 4296 4437 8733 3170 1903 5073 6976 2049 9025 1074 99 1173 1272 2445 3717 6162 9879 6041 5920 1961 7881 9842 7723 7565 5288 2853 8141 994 9135

(前3个词1,1,2故意遗漏。)第70个词是9135

时间是O(n),内存是O(1)。