Why is such complex code emitted for dividing a signed integer by a power of two?

后端 未结 3 801
囚心锁ツ
囚心锁ツ 2020-12-28 12:17

When I compile this code with VC++10:

DWORD ran = rand();
return ran / 4096;

I get this disassembly:

299: {
300:    DWORD r         


        
相关标签:
3条回答
  • 2020-12-28 12:44

    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.

    0 讨论(0)
  • 2020-12-28 12:50

    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.

    0 讨论(0)
  • 2020-12-28 12:54

    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.

    0 讨论(0)
提交回复
热议问题