I saw some code (in arc4random.c of libbsd) calculating 2**32 % x. A cleaned up version is below:
uint32_t x;
...
if (x >= 2) {
/* Calculate (2**32 % x) avoiding 64-bit math */
if (x > 0x80000000)
mod_res = 1 + ~x; /* 2**32 - x */
else {
/* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
mod_res = ((0xffffffff - (x * 2)) + 1) % x;
}
}
While the reasoning makes sense, my question is whether are there some obscure reasons not to use a simpler:
uint32_t x;
...
if (x >= 2) {
/* Calculate (2**32 % x) avoiding 64-bit math */
mod_res = -x % x;
}
Your code won’t work on a machine where
intis larger than 32 bits. In this case, in the expression-x, the operand would be promoted tointtype, and thus become signed. This would cause the result of the expression-x % xto always be zero.This behavior is due to C’s integer promotion rules, which state that if an
intcan represent all values of an operand, then that operand will be promoted to anint. While this always preserves value, it may change the signedness of the type.On a compiler with 32-bit
ints it would work correctly, becauseunsigned intwould not be promoted toint, and so-xwould be equal to2**32 - x.Your version can be fixed by casting the promoted value back to unsigned:
Here is an example demonstrating this with a 16-bit type on a machine with 32-bit ints.