Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to do (A*B) mod M without overflow for unsigned long long A and B?

I don't want the nightmare of installing GMP on Windows.

I have two numbers A and B, unsigned long longs, on the order of magnitude 10^10 or so at most, but even when doing ((A%M)*(B%M))%M, I get integer overflow.

Are there homebrew functions for calculating (A*B)%M for larger numbers?

like image 319
John Smith Avatar asked Nov 20 '12 00:11

John Smith


People also ask

How do you avoid overflow in multiplication?

We can multiply recursively to overcome the difficulty of overflow. To multiply a*b, first calculate a*b/2 then add it twice. For calculating a*b/2 calculate a*b/4 and so on (similar to log n exponentiation algorithm).

How can overflow be prevented?

One very good way to prevent integer overflows is to use int64_t to implement integers. In most case, 64-bits ints will not commit overflow, unlike their 32-bits counterparts. There is actually very few downsides in using int64_t instead of int32_t .

What causes unsigned overflow?

Therefore, unsigned overflow results from any operation that crosses the divide between 2N-1 and 0. Stated more plainly, if performing addition (which should make the result larger) produces a smaller result, the addition caused unsigned overflow.

Does unsigned int overflow?

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.


1 Answers

If the modulus M is sufficiently smaller than ULLONG_MAX (which is the case if it's in the region of 10^10), you can do it in three steps by splitting one of the factors in two parts. I assume that A < M and B < M, and M < 2^42.

// split A into to parts
unsigned long long a1 = (A >> 21), a2 = A & ((1ull << 21) - 1);
unsigned long long temp = (a1 * B) % M;   // doesn't overflow under the assumptions
temp = (temp << 21) % M;                  // this neither
temp += (a2*B) % M;                       // nor this
return temp % M;

For larger values, you can split the factor in three parts, but if the modulus becomes really close to ULLONG_MAX it becomes ugly.

like image 141
Daniel Fischer Avatar answered Sep 30 '22 22:09

Daniel Fischer