给定整数a,b,c和m,我需要计算(a*b*c)%m
,其中a,b,c和m可以大到10 ^ 18。我知道如何计算(a * b)%m如下:
unsigned long long mulmod(unsigned long long a,unsigned long long b,unsigned long long c){
unsigned long long x = 0,y=a%c;
while(b > 0){
if(b%2 == 1) {
x = (x+y)%c;
}
y = (y*2)%c;
b /= 2;
}
return x%c;
}
可以为(a*b*c)%m
完成这样的事情吗?
答案 0 :(得分:3)
假设您的函数mulmod(a, b, m)
在返回(a * b) / m
提醒的位置工作。您可以按(a * b * c) % m
mulmod(mulmod(a, b, m), c, m)
你可能为什么这样做?为什么(a * b * c) % m
等于((a * b) % m) * c % m
。您可以证明如下:
让
Let a * b = dm + r c = em + q Therefore, a * b * c = (dm + r) * (em + q) = (dem + dq + er)m + rq So (a * b * c) % m = [(de + r + q)m + rq] % m = rq % m How about [(a * b) % m] * c % m We know that (a * b) % m = r Therefore [(a * b) % m] * c % m = [r * (em + q)] % m = (rem + rq) % m = rq % m Hence, [(a * b) % m] * c % m and (a * b * c) % m are the same
答案 1 :(得分:1)
模运算的乘法属性如下:
ab mod m = (a mod m)(b mod m) mod m // Rule 1
由此得出:
abc mod m = (ab mod m)(c mod m) mod m // Expand (ab)c mod m
= ((a mod m)(b mod m) mod m mod m)(c mod m) mod m // Expand ab mod m
= ((a mod m)(b mod m) mod m)(c mod m) mod m // Trim extra mod m
= (a mod m)(b mod m)(c mod m) mod m // Reverse rule 1 with
// a' = (a mod m)(b mod m)
// b' = c mod m
这表明实现三向模乘的两个选项。最简单的是将所有三个mod m项相乘,并对结果进行修改,但如果修改每个中间结果,则不太可能遇到溢出。假设C ++:
template <typename T, size_t N>
T mulmod(T (&multiplicands)[N], T m) {
T result = 1;
for (T n : multiplicands)
result = (result * (n % m)) % m;
return result;
}
int nums = {123, 345, 656, 841};
std::cout << mulmod(nums, 373) << "\n"; // Prints 88