例如,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位数据。
答案 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
类型。
另外,你可以使用稍微不同的(但实际上使用相同的数学)方法对我来说似乎更明显 - 斐波那契数字矩阵公式
要计算矩阵的N
幂,您可以通过对所有运算模B
求平方来使用取幂。