Avoiding overflow in integer multiplication followed by division

后端 未结 4 1678
失恋的感觉
失恋的感觉 2020-12-31 08:32

I have two integral variables a and b and a constant s resp. d. I need to calculate the value of (a*b)>>s

相关标签:
4条回答
  • 2020-12-31 08:58

    If there isn't a larger type, you will either need to find a big-int style library, or deal with it manually, using long multiplication.

    For instance, assume a and b are 16-bit. Then you can rewrite them as a = (1<<8)*aH + aL, and b = (1<<8)*bH + bL (where all the individual components are 8-bit numbers). Then you know that the overall result will be:

    (a*b) = (1<<16)*aH*bH
          + (1<<8)*aH*bL
          + (1<<8)*aL*bH
          + aL*bL
    

    Each of these 4 components will fit a 16-bit register. You can now perform e.g. right-shifts on each of the individual components, being careful to deal with carries appropriately.

    0 讨论(0)
  • 2020-12-31 08:59

    In certain cases (historically LCG random number generators with selected constants), it is possible to do what you want, for some values of a and d.

    This is called Schrage's method, see eg. there.

    0 讨论(0)
  • 2020-12-31 09:05

    I haven't exhaustively tested this, but could you do the division first, then account for the remainder, at the expense of extra operations? Since d is a power of two, all the divisions can be reduced to bitwise operations.

    For example, always assume a > b (you want to divide the larger number first). Then a * b / d = ((a / d) * b) + (((a % d) * b) / d)

    0 讨论(0)
  • 2020-12-31 09:09

    If the larger type is just 64 bits then the straight forward solution will most likely result in efficient code. On x86 CPUs any multiplication of two 32 bit numbers will give the overflow in another register. So if your compiler understands that, it can generate efficient code for Int64 result=(Int64)a*(Int64)b.

    I had the same problem in C#, and the compiler generated pretty good code. And C++ compilers typically create better code than the .net JIT.

    I recommend writing the code with the casts to the larger types and then inspect the generated assembly code to check if it's good.

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