When I compile this code with VC++10:
DWORD ran = rand();
return ran / 4096;
I get this disassembly:
299: {
300: DWORD ran = rand();
00403940 call dword ptr [__imp__rand (4050C0h)]
301: return ran / 4096;
00403946 shr eax,0Ch
302: }
00403949 ret
which is clean and concise and replaced a division by a power of two with a logical right shift.
Yet when I compile this code:
int ran = rand();
return ran / 4096;
I get this disassembly:
299: {
300: int ran = rand();
00403940 call dword ptr [__imp__rand (4050C0h)]
301: return ran / 4096;
00403946 cdq
00403947 and edx,0FFFh
0040394D add eax,edx
0040394F sar eax,0Ch
302: }
00403952 ret
that performs some manipulations before doing a right arithmetic shift.
What's the need for those extra manipulations? Why is an arithmetic shift not enough?
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.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With