二进制供电给我一个错误的结果

Binary powering giving me a wrong result

我的二进制供电功能有问题。包含结果的变量在执行乘法时溢出并给我一个错误的结果。当源值大于 4,312,952,827 时会发生这种情况。那么我该如何解决这个问题呢?这是我的函数的代码。

unsigned long long binpow(unsigned long long a, unsigned long long n, unsigned long long m)
{
    unsigned long long res;
    res=1;
    while (n)
    {
        if (n & 1)
        {
            res=(res*a)%m;
            n--;
        }
        a=(a*a)%m;
        n >>= 1;
    }
    return res;
}

您的余数和模数都超过了 unsigned long long 的宽度(移动了 m)。

您可以使用像 unsigned __int128 这样的编译器扩展类型来推迟这个问题,它会产生 4,312,952,827 的正确结果。

unsigned __int128 binpow(unsigned __int128 a, unsigned __int128 n, unsigned __int128 m)
{
    unsigned __int128 res;
    res = 1;
    while (n)
        {
            if (n & 1)
                {
                    res = (res*a)%m;
                    n--;
                }
            a = (a*a) % m;
            n >>= 1;
        }
    return res;
}

或者,如果您想以安全的方式处理大量数字,可以使用 gmplib

这样的通用 bignum 库

表达式 a*a 需要的空间是源大小的两倍。在您的场景 4,312,952,827 > 2^32-1 中,因此您超出了 unsigned long long 的范围。

实现模幂运算的二进制阶梯的经验法则是能够对至少是参数数据类型两倍的范围执行算术运算,因此在您的情况下它是 128 位。