Ways to do modulo multiplication with primitive types

后端 未结 7 2101
野趣味
野趣味 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 08:44

    a * b % m equals a * b - (a * b / m) * m

    Use floating point arithmetic to approximate a * b / m. The approximation leaves a value small enough for normal 64 bit integer operations, for m up to 63 bits.

    This method is limited by the significand of a double, which is usually 52 bits.

    uint64_t mod_mul_52(uint64_t a, uint64_t b, uint64_t m) {
        uint64_t c = (double)a * b / m - 1;
        uint64_t d = a * b - c * m;
    
        return d % m;
    }
    

    This method is limited by the significand of a long double, which is usually 64 bits or larger. The integer arithmetic is limited to 63 bits.

    uint64_t mod_mul_63(uint64_t a, uint64_t b, uint64_t m) {
        uint64_t c = (long double)a * b / m - 1;
        uint64_t d = a * b - c * m;
    
        return d % m;
    }
    

    These methods require that a and b be less than m. To handle arbitrary a and b, add these lines before c is computed.

    a = a % m;
    b = b % m;
    

    In both methods, the final % operation could be made conditional.

    return d >= m ? d % m : d;
    

提交回复
热议问题