C++ c+中大数的模乘+;
我有三个整数A,B(小于10^12)和C(小于10^15)。我想计算(A*B)%C。我知道C++ c+中大数的模乘+;,c++,algorithm,multiplication,modular,C++,Algorithm,Multiplication,Modular,我有三个整数A,B(小于10^12)和C(小于10^15)。我想计算(A*B)%C。我知道 (A * B) % C = ((A % C) * (B % C)) % C 但如果A=B=10^11,则上述表达式将导致整数溢出。以上情况有没有简单的解决方案,或者我必须使用快速乘法算法 如果我必须使用快速乘法算法,那么我应该使用哪种算法 编辑:我在中尝试了上述问题(这不会导致溢出,不确定原因),但答案不应该是零吗 提前感谢。更新:修复了设置%c高位时的错误。(帽子提示:凯文·霍普斯) 如果您正在寻找“
(A * B) % C = ((A % C) * (B % C)) % C
但如果A=B=10^11,则上述表达式将导致整数溢出。以上情况有没有简单的解决方案,或者我必须使用快速乘法算法
如果我必须使用快速乘法算法,那么我应该使用哪种算法
编辑:我在中尝试了上述问题(这不会导致溢出,不确定原因),但答案不应该是零吗
提前感谢。更新:修复了设置%c高位时的错误。(帽子提示:凯文·霍普斯) 如果您正在寻找“简单过快速”,则可以使用以下方法:
typedef unsigned long long u64;
u64 multiplyModulo(u64 a, u64 b, u64 c)
{
u64 result = 0;
a %= c;
b %= c;
while(b) {
if(b & 0x1) {
result += a;
result %= c;
}
b >>= 1;
if(a < c - a) {
a <<= 1;
} else {
a -= (c - a);
}
}
return result;
}
typedef无符号长u64;
u64多线程(u64 a、u64 b、u64 c)
{
u64结果=0;
a%=c;
b%=c;
而(二){
if(b&0x1){
结果+=a;
结果%=c;
}
b>>=1;
if(a a您可以使用Schrage的方法解决此问题。这允许您将两个有符号数a
和z
乘以一定的模m
,而不会生成大于该模的中间数
它基于模m
的近似因式分解
m = aq + r
i、 e
及
其中[]
表示整数部分。如果r
和0
,则a(z mod q)
和r[z/q]
都在0,…,m范围内− 1
和
az mod m = a(z mod q) − r[z / q]
如果为负值,则添加m
[此技术常用于线性全等随机数生成器]。根据您的公式和以下变化:
(A + B) mod C = ((A mod C) + (B mod C)) mod C
您可以使用分而治之的方法开发一种既简单又快速的算法:
#include <iostream>
long bigMod(long a, long b, long c) {
if (a == 0 || b == 0) {
return 0;
}
if (a == 1) {
return b;
}
if (b == 1) {
return a;
}
// Returns: (a * b/2) mod c
long a2 = bigMod(a, b / 2, c);
// Even factor
if ((b & 1) == 0) {
// [((a * b/2) mod c) + ((a * b/2) mod c)] mod c
return (a2 + a2) % c;
} else {
// Odd exponent
// [(a mod c) + ((a * b/2) mod c) + ((a * b/2) mod c)] mod c
return ((a % c) + (a2 + a2)) % c;
}
}
int main() {
// Use the min(a, b) as the second parameter
// This prints: 27
std::cout << bigMod(64545, 58971, 144) << std::endl;
return 0;
}
#包括
长bigMod(长a、长b、长c){
如果(a==0 | | b==0){
返回0;
}
如果(a==1){
返回b;
}
如果(b==1){
返回a;
}
//返回:(a*b/2)c模式
长a2=bigMod(a,b/2,c);
//偶数因子
如果((b&1)==0){
//[((a*b/2)c型)+((a*b/2)c型)]c型
返回(a2+a2)%c;
}否则{
//奇指数
//[(a/c模式)+(a/b/2)c模式)+(a/b/2)c模式]
返回((a%c)+(a2+a2))%c;
}
}
int main(){
//使用最小值(a,b)作为第二个参数
//这个数字是:27
std::cout对不起,但是当变量“a”包含设置了高位的值时,godel9的算法将产生错误的结果。这是因为“a在这种情况下,a和B是40位的数字,C是50位的数字,这在64位模式下不是问题,如果您有内在的或可以编写汇编代码来使用64位乘以64位的乘法,从而产生128位的结果(乘积实际上是80位),然后将128位被除数除以50位除数,得到50位余数(模)
根据处理器的不同,通过乘以81位(或更少)来实现除以50位常数可能会更快常数。再次假设64位处理器,需要4次乘法和一些加法,然后将4次乘法乘积的高位移位以生成商。然后将商乘以50位模数并减去(从80位乘积中)用于生成50位余数。只有当C足够大时,RHS才会溢出(这就是余数的奇妙之处)C++中的算术溢出通常是无噪声的——没有错误,只是发生了。当你看到你的输出是“代码>712049423024128”/代码>时,你会发现它。当你期待代码“0”/代码>。如果你想要快速的东西,我担心它必须是平台特定的。什么平台?你感兴趣吗?这是做指数运算,但问题是做乘法。不过,你可能可以在代码中将乘法改为加法,这应该会起作用。如果(b==0)返回0,你还需要使用;
是的!你说得对,感谢你注意到了(并感谢你没有对答案投反对票,尽管答案是值得的).我正确地更新了+1我认为这个版本的算法比公认的答案可读性更强(虽然更长),据我所知,答案也是一样。它工作正常,但算法速度非常慢:(此外,您可以将其用作递归算法,以包含所有r>=q
。对产品r*[z/q]
重复上述算法,使新值变为:a2=r
z2=[r/q]
这保证了a
值减少:a>r=a2
->a2
最终,当a=a>r
->rWhen“a”时如果设置了高位,则会产生不正确的结果。请参阅下面的我的帖子。对第一个加法的更正也会溢出,但代码的其余部分是正确的(并且下面关于左移的注释在当前版本的代码中是不正确的):if(result(A + B) mod C = ((A mod C) + (B mod C)) mod C
#include <iostream>
long bigMod(long a, long b, long c) {
if (a == 0 || b == 0) {
return 0;
}
if (a == 1) {
return b;
}
if (b == 1) {
return a;
}
// Returns: (a * b/2) mod c
long a2 = bigMod(a, b / 2, c);
// Even factor
if ((b & 1) == 0) {
// [((a * b/2) mod c) + ((a * b/2) mod c)] mod c
return (a2 + a2) % c;
} else {
// Odd exponent
// [(a mod c) + ((a * b/2) mod c) + ((a * b/2) mod c)] mod c
return ((a % c) + (a2 + a2)) % c;
}
}
int main() {
// Use the min(a, b) as the second parameter
// This prints: 27
std::cout << bigMod(64545, 58971, 144) << std::endl;
return 0;
}