如何在 C++ (g++)中使用 A,B<=10^18 计算 Fibonacci(A) mod B [关闭]
Posted
技术标签:
【中文标题】如何在 C++ (g++)中使用 A,B<=10^18 计算 Fibonacci(A) mod B [关闭]【英文标题】:How can I calculate Fibonacci(A) mod B with A,B<=10^18 in C++ (g++) [closed] 【发布时间】:2017-09-27 13:34:33 【问题描述】:例如,A=10^17, B=10^17 ( 通常,在上面的算法中,计算 F(2n) 和计算 F(2n+1) 的计算超过了 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.
你知道在新的 C++14(g++8.3.0 或 llvm-clang C++)中使用一些类型来避免溢出吗? 我试过 __float128 比 long double 好,但没有成功。 (参见上面的 g++ 代码) 我听说存在 __int128 和 __int256 没有 printf 的可能性,但我没有尝试过。 它们在 g++ 8.3.0 中是否可用,或者是否有其他快速方法来处理 128 位整数来进行您能想到的中间计算? (时间性能很重要)
#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;
使用 __float128 我无法有效地实现模数,a、b、c、d 必须存储 128 位数据。
【问题讨论】:
Storing numbers with higher precision in C的可能重复 “Fibonnacci(A) 超过 long long int 类型”——无关紧要,您只需首先对 B 取模即可。 @harold +1:然后,这是 mathoverflow 的问题。 Huge fibonacci modulo m C++ 的可能重复项,或者您可以选择其他算法 清晰的解释(但没有代码):***.com/questions/40556760/… 【参考方案1】:计算不需要任何浮点类型。您只能使用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;
其次,您需要在几乎所有算术运算中添加模运算。您肯定需要在相应的操作中添加% mod
来替换这些循环while(c>=mod)c-=mod
(它们可能非常慢)。
__float_128
的代码替换为 long long
并使用适当的模运算:https://ideone.com/t6R7Tf
您可以做的另一件事是使用(如 cmets 中所述)Boost.Multiprecision
或非标准 __int128
类型(如果支持)而不是具有复杂乘法的 long long
类型。
此外,您可以使用稍微不同(但实际上使用相同的数学)的方法,这对我来说似乎更明显 - 斐波那契数矩阵公式
要计算矩阵的N
th 次方,您可以通过对所有以B
为模的运算进行平方来使用求幂。
【讨论】:
这与我在帖子中提到的斐波那契快速加倍算法的问题相同。问题更多在于我可以用来计算它的类型。我见过 __float128 但我认为我不能用这个浮点数实现所有 int 变量。 问题提到了g++。假设 x86_64,__int128
会使乘法更容易。或者使用 Boost.Multiprecision 类型。
注意:这本质上与问题中提供的快速加倍算法相同,性能相同。
@JamesKPolk,没错。问题的较早版本没有包含任何代码或实现细节,我提出了对我个人来说似乎更明显的矩阵方法。
Here 是另一个有趣的表述。以上是关于如何在 C++ (g++)中使用 A,B<=10^18 计算 Fibonacci(A) mod B [关闭]的主要内容,如果未能解决你的问题,请参考以下文章