c++ - 通过平方进行模幂运算的溢出可能性

标签 c++ algorithm primes exponentiation

我希望实现 fermat's little theorem用于主要测试。这是我编写的代码:

lld expo(lld n, lld p) //2^p mod n
{
    if(p==0)
        return 1;
    lld exp=expo(n,p/2);
    if(p%2==0)
        return (exp*exp)%n;
    else
        return (((exp*exp)%n)*2)%n;
}

bool ifPseudoPrime(lld n)
{
    if(expo(n,n)==2)
        return true;
    else
        return false;
}

注意:我取了a(<=n-1)的值作为2 .

现在,数字 n 可以大到 10^18 .这意味着变量 exp可以达到 10^18 附近的值.这进一步意味着表达式 (exp*exp)最高可达10^36从而导致溢出。我该如何避免这种情况。

我对此进行了测试,它运行良好直到 10^9 .我正在使用 C++

最佳答案

如果模数接近您可以使用的最大整数类型的限制,事情就会变得有些复杂。如果您不能使用实现双整数运算的库,您可以通过将因子拆分为低阶和高阶部分来自行进行模乘法。

如果模数m太大了 2*(m-1)溢出,事情变得非常挑剔,但如果 2*(m-1)不会溢出,可以忍受。

让我们假设您拥有并使用 64 位无符号整数类型。

您可以通过将因子拆分为低 32 位和高 32 位来计算模积,然后乘积拆分为

a = a1 + (a2 << 32)    // 0 <= a1, a2 < (1 << 32)
b = b1 + (b2 << 32)    // 0 <= b1, b2 < (1 << 32)
a*b = a1*b1 + (a1*b2 << 32) + (a2*b1 << 32) + (a2*b2 << 64)

计算a*b (mod m)m <= (1 << 63) , 减少四个产品中的每一个模 m ,

p1 = (a1*b1) % m;
p2 = (a1*b2) % m;
p3 = (a2*b1) % m;
p4 = (a2*b2) % m;

合并这些转变的最简单方法是

for(i = 0; i < 32; ++i) {
    p2 *= 2;
    if (p2 >= m) p2 -= m;
}

p3 相同p4 的 64 次迭代.然后

s = p1+p2;
if (s >= m) s -= m;
s += p3;
if (s >= m) s -= m;
s += p4;
if (s >= m) s -= m;
return s;

这种方式不是很快,但是对于这里需要的少数乘法,它可能足够快了。应该通过减少轮类次数来获得小的加速;先计算(p4 << 32) % m ,

for(i = 0; i < 32; ++i) {
    p4 *= 2;
    if (p4 >= m) p4 -= m;
}

然后所有p2 , p3p4 的当前值需要乘以 232m ,

p4 += p3;
if (p4 >= m) p4 -= m;
p4 += p2;
if (p4 >= m) p4 -= m;
for(i = 0; i < 32; ++i) {
    p4 *= 2;
    if (p4 >= m) p4 -= m;
}
s = p4+p1;
if (s >= m) s -= m;
return s;

关于c++ - 通过平方进行模幂运算的溢出可能性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16426557/

相关文章:

c++ - 如何强制使用模板特化?

algorithm - 这个 for 循环语句的运行时间?

java - B树修订

functional-programming - 函数式语言中的质因数分解

c - 为什么我在调用 realloc() 后得到模运算的浮点异常?

c++ - 背景图像上的 OpenGL 透明对象

C++ - 模板类、头文件和重复错误

c++ - 使用 ifstream 加载文件时出错 - 只加载了一小部分

java - 伽罗瓦域 GF(4) 中乘法的恒定时间

python - python中除法的奇怪行为