4 ms·
Let’s look at the free draft version of C99 ( http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pd
by strenholme 5y ago
Let’s look at the free draft version of C99 ( http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf ). On PDF page 94 (physical page number 82), we cover integers:
If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a
For division:
The result of the / operator is the quotient from the division of the first operand by the second
Which is remarkably vague. Presumably, they are doing the kind of third grade math where we get a quotient and a remainder (Euclidean division). So, 1/3 is 0, 2/3 is 0, 3/3 is 1, 4/3 is 1, 5/3 is 1, 6/3 is 2, etc.
That in mind, let’s look at -1 % 3 (is 2 when doing a proper modulo operation)
With integers:
(-1 / 3) is 0 (1 / 3 is “0 remainder 1” and multiplied by -1 still gives us 0)
This in mind, the modulo (-1 % 3) needs to give us -1:
(0 * 3) + -1 = -1
So a%b is negative here.
There are some ways to work around this and get a proper modulo.
One common case is to get something modulo a power of 2. This will give us a modulo, 20 in this case, as per the C standard:
#include <stdint.h>
uint32_t foo = 12;
printf("%d\n",-foo % 32);
The reason is because, as per PDF page 55 (page 43) of that draft C99 standard:
if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
So, since foo is unsigned, and a 32-bit int, -foo is -12 + 4294967296, or 4294967284. 4294967284 % 32 as per the spec above is 20, i.e. -12 mod 32.
This trick only works if we modulo a number by a power of 2.
Yes, I have used this trick when writing “golfed” C code which needs to do a circular rotate:
uint32_t r=12,g=1;g=g>>r|g<<-r%32;