Search code examples
visual-c++x86multiplicationbigintegerintrinsics

_umul128 on Windows 32 bits


In Visual C++, _umul128 is undefined when targeting 32-bit Windows.

How can two unsigned 64-bit integers be multiplied when targeting Win32? The solution only needs to work on Visual C++ 2017 targeting 32-bit Windows.


Solution

  • I found the following code (from xmrrig), which seems to do the job just fine:

    static inline uint64_t __umul128(uint64_t multiplier, uint64_t multiplicand, 
        uint64_t *product_hi) 
    {
        // multiplier   = ab = a * 2^32 + b
        // multiplicand = cd = c * 2^32 + d
        // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
        uint64_t a = multiplier >> 32;
        uint64_t b = multiplier & 0xFFFFFFFF;
        uint64_t c = multiplicand >> 32;
        uint64_t d = multiplicand & 0xFFFFFFFF;
    
        //uint64_t ac = a * c;
        uint64_t ad = a * d;
        //uint64_t bc = b * c;
        uint64_t bd = b * d;
    
        uint64_t adbc = ad + (b * c);
        uint64_t adbc_carry = adbc < ad ? 1 : 0;
    
        // multiplier * multiplicand = product_hi * 2^64 + product_lo
        uint64_t product_lo = bd + (adbc << 32);
        uint64_t product_lo_carry = product_lo < bd ? 1 : 0;
        *product_hi = (a * c) + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry;
    
        return product_lo;
    }