C++ 中的 int(或长长)溢出如何影响模数

How does int(or long long) overflow in c++ affect modulus?

本文关键字:影响 何影响 中的 C++ 溢出 int      更新时间:2023-10-16

假设我有两个长长,a和b,我需要相乘,然后得到一些大k的值mod k,这样a,b和k都在长整型的范围内,而不是int。为简单起见,a、b <k。>

因此,代码将是:

long long a, b, k;
cin >> a >> b >> k;
cout << (a * b)%k << "n";

但是,由于 a 和 b 太大了,如果你像上面一样乘法,它溢出并变成负数,那么 mod k 将是一个负数并且不正确。

如何确保值 mod k 正确?

编辑:作为奖励,这在Java中是如何工作的?是否如预期的那样相同?还是需要BigInteger?

许多编译器提供 128 位积分类型。例如,使用g++您可以创建一个函数

static inline int64_t mulmod(int64_t x, int64_t y, int64_t m)
{
    return ( (__int128_t)x * y) % m;
}

旁白:如果可以的话,在做模算术时尽量坚持使用无符号整数类型。整数除法的舍入行为使得在涉及有符号值时使用%非常尴尬。

如果您知道值小于 ULONGLONG_MAX/2(因此添加不会溢出),则可以一次乘以一位:

unsigned long long mulmod(unsigned long long a, unsigned long unsigned long b, long long m) {
    unsigned long long rv = 0;
    a %= m;
    b %= m;
    while (b) {
        if (b&1) { rv += a; if (rv >= m) rv -= m; }
        a += a; if (a >= m) a -= m;
        b >>= 1; }
    return rv; }

如果您知道自己使用的是 gcc/x86_64,可以尝试:

unsigned long mulmod(unsigned long a, unsigned long b, unsigned long m) {
    unsigned long rv;
    asm ("mulq %2; divq %3" : "=d"(rv), "+a"(a): "S"(b), "c"(m));
    return rv;
}

这将工作到ULONG_MAX

如果你的数字比这个数字大,你需要去一个多精度库,如GMP。