When I compile this code with VC++10:
DWORD ran = rand();
return ran / 4096;
I get this disassembly:
299: {
300: DWORD r
the "extra manipulations" compensate for the fact that arithmetic right-shift rounds the result toward negative infinity, whereas division rounds the result towards zero.
For example, -1 >> 1
is -1
, whereas -1/2
is 0
.
From the C standard:
When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded.105) If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a; otherwise, the behavior of both a/b and a%b is undefined.
It's not hard to think of examples where negative values for a don't follow this rule with pure arithmetic shift. E.g.
(-8191) / 4096 -> -1
(-8191) % 4096 -> -4095
which satisfies the equation, whereas
(-8191) >> 12 -> -2 (assuming arithmetic shifting)
is not division with truncation, and therefore -2 * 4096 - 4095
is most certainly not equal to -8191.
Note that shifting of negative numbers is actually implementation-defined, so the C expression (-8191) >> 12
does not have a generally correct result as per the standard.
The reason is that unsigned division by 2^n can be implemented very simply, whereas signed division is somewhat more complex.
unsigned int u;
int v;
u / 4096
is equivalent to u >> 12
for all possible values of u
.
v / 4096
is NOT equivalent to v >> 12
- it breaks down when v < 0
, as the rounding direction is different for shifting versus division when negative numbers are involved.