c ++中int(或long long)溢出如何影响模数?

时间:2015-06-14 20:50:01

标签: c++ long-integer modulus integer-overflow

假设我有两个长long,a和b,我需要乘以,然后得到某个大k的值mod k,这样a,b和k都在long long范围内,但不是INT。为简单起见,a,b< ķ。

因此代码将是:

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

然而,由于a和b如此之大,如果你像上面那样相乘,并且溢出并变为负数,则mod k将是负数并且不正确。

如何确保值mod k正确?

编辑:作为奖励,这在Java中如何运作?是否与预期一样?或者需要BigInteger吗?

2 个答案:

答案 0 :(得分:1)

如果你知道这些值小于ULONGLONG_MAX/2(所以添加赢了#t; t溢出),你可以一次乘以一位:

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

答案 1 :(得分:1)

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

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

除此之外:如果可以的话,在进行模运算时,请尝试坚持使用无符号整数类型。整数除法的舍入行为使得%在涉及有符号值时非常笨拙。