Ways to do modulo multiplication with primitive types

后端 未结 7 2012
野趣味
野趣味 2020-12-05 08:13

Is there a way to build e.g. (853467 * 21660421200929) % 100000000000007 without BigInteger libraries (note that each number fits into a 64 bit integer but the

相关标签:
7条回答
  • 2020-12-05 09:07

    Keith Randall's answer is good, but as he said, a caveat is that it works only if m is 63 bits or less.

    Here is a modification which has two advantages:

    1. It works even if m is 64 bits.
    2. It doesn't need to use the modulo operation, which can be expensive on some processors.

    (Note that the res -= m and temp_b -= m lines rely on 64-bit unsigned integer overflow in order to give the expected results. This should be fine since unsigned integer overflow is well-defined in C and C++. For this reason it's important to use unsigned integer types.)

    uint64_t mulmod(uint64_t a, uint64_t b, uint64_t m) {
        uint64_t res = 0;
        uint64_t temp_b;
    
        /* Only needed if b may be >= m */
        if (b >= m) {
            if (m > UINT64_MAX / 2u)
                b -= m;
            else
                b %= m;
        }
    
        while (a != 0) {
            if (a & 1) {
                /* Add b to res, modulo m, without overflow */
                if (b >= m - res) /* Equiv to if (res + b >= m), without overflow */
                    res -= m;
                res += b;
            }
            a >>= 1;
    
            /* Double b, modulo m */
            temp_b = b;
            if (b >= m - b)       /* Equiv to if (2 * b >= m), without overflow */
                temp_b -= m;
            b += temp_b;
        }
        return res;
    }
    
    0 讨论(0)
提交回复
热议问题