Integer division by 7

前端 未结 1 2025
误落风尘
误落风尘 2020-12-30 05:53

Source my answer in:

Is this expression correct in C preprocessor

I\'m a little bit out of my forte here, and I\'m trying to understand how this particular o

相关标签:
1条回答
  • 2020-12-30 06:29

    The first part of the algorithm is multiplying by an approximation to the reciprocal of 7. In this case, we're approximating computing the reciprocal with an integer multiplication and a right bit-shift.

    First, we see the value -1840700269 (octal -015555555555) as a 32-bit integer. If you read this as an unsigned 32 bit integer, it has value 2454267027 (octal 22222222223). It turns out that 2454267027 / 2^34 is a very close integer approximation to 1/7.

    Why do we pick this number and this particular power of 2? The larger the integers we use, the closer the approximation is. In this case, 2454267027 seems to be the largest integer (satisfying the above property) with which you can multiply a signed 32-bit int without overflowing a 64-bit int.

    Next, if we immediately right shift with >> 34 and store the result in a 32-bit int, we're going to lose the accuracy in the two lowest-order bits. Those bits are necessary to determining the right floor for integer division.

    I'm not sure the second line was translated correctly from the x86 code. At that point, temp is approximately num * 4/7, so num * 4/7 + num to that and bit-shifting is going to give you approximately num * 1/7 + num * 1/4, a quite large error.

    For example, take as input 57, where 57 // 7 = 8. I verified the below in code as well:

    • 57 * 2454267027 = 139893220539
    • 139893220539 >> 32 = 32 (approx 57 * 4/7 = 32.5714... at this point)
    • 32 + 57 = 89
    • 89 >> 2 = 22 (huh?? Nowhere close to 8 at this point.)

    Anyway, for the last line, it is an adjustment we make after computing signed integer division this way. I quote from the section from Hacker's delight on signed division:

    The code most naturally computes the floor division result, so we need a correction to make it compute the conventional truncated toward 0 result. This can be done with three computational instructions by adding to the dividend if the dividend is negative.

    In this case (referring to your other post) it seems you are doing a signed shift, so it will subtract -1 in the case of a negative number; giving the result of +1.

    This isn't even all you can do; here's an even crazier blog post about how to divide by 7 with just a single multiplication.

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