How to avoid overflow in expr. A * B - C * D

后端 未结 15 996
萌比男神i
萌比男神i 2021-01-29 18:18

I need to compute an expression which looks like: A*B - C*D, where their types are: signed long long int A, B, C, D; Each number can be really big (not

15条回答
  •  走了就别回头了
    2021-01-29 18:52

    While a signed long long int will not hold A*B, two of them will. So A*B could be decomposed to tree terms of different exponent, any of them fitting one signed long long int.

    A1=A>>32;
    A0=A & 0xffffffff;
    B1=B>>32;
    B0=B & 0xffffffff;
    
    AB_0=A0*B0;
    AB_1=A0*B1+A1*B0;
    AB_2=A1*B1;
    

    Same for C*D.

    Folowing the straight way, the subraction could be done to every pair of AB_i and CD_i likewise, using an additional carry bit (accurately a 1-bit integer) for each. So if we say E=A*B-C*D you get something like:

    E_00=AB_0-CD_0 
    E_01=(AB_0 > CD_0) == (AB_0 - CD_0 < 0) ? 0 : 1  // carry bit if overflow
    E_10=AB_1-CD_1 
    ...
    

    We continue by transferring the upper-half of E_10 to E_20 (shift by 32 and add, then erase upper half of E_10).

    Now you can get rid of the carry bit E_11 by adding it with the right sign (obtained from the non-carry part) to E_20. If this triggers an overflow, the result wouldn't fit either.

    E_10 now has enough 'space' to take the upper half from E_00 (shift, add, erase) and the carry bit E_01.

    E_10 may be larger now again, so we repeat the transfer to E_20.

    At this point, E_20 must become zero, otherwise the result won't fit. The upper half of E_10 is empty as result of the transfer too.

    The final step is to transfer the lower half of E_20 into E_10 again.

    If the expectation that E=A*B+C*D would fit the signed long long int holds, we now have

    E_20=0
    E_10=0
    E_00=E
    

提交回复
热议问题