Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ c+中大数的模乘+;_C++_Algorithm_Multiplication_Modular - Fatal编程技术网

C++ 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(小于10^12)和C(小于10^15)。我想计算(A*B)%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(aa您可以使用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;
}