如何计算Fibonacci(A)mod B,A,B <= 10 ^ 18 in C ++(g ++)

时间:2017-09-27 13:34:33

标签: c++ algorithm math implementation

例如,A = 10 ^ 17,B = 10 ^ 17(<64位) 通常,fibonnacci(A)超过long long int类型。 计算它的算法应该是斐波那契快速加倍:

  

F(0)= 0,F(1)= 1   F(2n)= F(n)(2 * F(n + 1)-F(n))   F(2n + 1)= F(n) 2 + F(n + 1) 2

但如何将其扩展为大数?

#include <bits/stdc++.h>
using namespace std;

__float128 a,b,c,d;
long long mod;

void fast_fib(long long n,long long ans[]){
    if(n == 0){
        ans[0] = 0;
        ans[1] = 1;
        return;
    }
    fast_fib((n/2),ans);
    a = ans[0];             /* F(n) */
    b = ans[1];             /* F(n+1) */
    c = 2*b - a;
    if(c < 0) c += mod;
    c = (a * c);      /* F(2n) */
    while(c>=mod)c-=mod;
    d = (a*a + b*b);  /* F(2n + 1) */
    while(d>=mod)d-=mod;
    if(n%2 == 0){
        ans[0] = c;
        ans[1] = d;
    }
    else{
        ans[0] = d;
        ans[1] = c+d;
    }
}

int main(){
  int T=1000;
  long long n;
  while(T--){
    scanf("%lld %lld",&n,&mod);
    long long ans[2]={0};
    fast_fib(n,ans);
    printf("%lld\n", ans[0]);
  }
  return 0;
}

with __float_128我无法有效地实现模数,a,b,c,d必须存储128位数据。

1 个答案:

答案 0 :(得分:2)

计算时不需要任何浮点类型。您只能使用long long类型。首先,您需要一个函数可以将两个long long个数字(小于10^18)与B模数相乘。这可以使用与exponentiation by squaring方法类似的方法完成:

long long multiply(long long a, long long b, long long M) {
    long long res = 0;
    long long d = a;

    while (b > 0) {
        if (b & 1) {
            res = (res + d) % M;
        }
        b /= 2;
        d = (d + d) % M;
    }
    return res;
}

其次,您需要为几乎所有算术运算添加模运算。你肯定需要在相应的操作中添加while(c>=mod)c-=mod来替换这些循环% mod(它们可能非常慢)。

__float_128替换为long long并使用适当的模块化算法的代码:https://ideone.com/t6R7Tf

您可以做的另一件事是使用(如评论中所述)Boost.Multiprecision或非标准__int128类型(如果支持)而不是具有复杂乘法的long long类型。

另外,你可以使用稍微不同的(但实际上使用相同的数学)方法对我来说似乎更明显 - 斐波那契数字矩阵公式

enter image description here

要计算矩阵的N幂,您可以通过对所有运算模B求平方来使用取幂。