How can I add and subtract 128 bit integers in C or C++ if my compiler does not support them?

后端 未结 7 737
我在风中等你
我在风中等你 2020-11-28 11:07

I\'m writing a compressor for a long stream of 128 bit numbers. I would like to store the numbers as differences -- storing only the difference between the numbers rather th

7条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-11-28 11:44

    Having stumbled across this relatively old post entirely by accident, I thought it pertinent to elaborate on Volte's previous conjecture for the benefit of inexperienced readers.

    Firstly, the signed range of a 128-bit number is -2127 to 2127-1 and not -2127 to 2127 as originally stipulated.

    Secondly, due to the cyclic nature of finite arithmetic the largest required differential between two 128-bit numbers is -2127 to 2127-1, which has a storage prerequisite of 128-bits, not 129. Although (2127-1) - (-2127) = 2128-1 which is clearly greater than our maximum 2127-1 positive integer, arithmetic overflow always ensures that the nearest distance between any two n-bit numbers always falls within the range 0 to 2n-1 and thus implicitly -2n-1 to 2n-1-1.

    In order to clarify, let us first examine how a hypothetical 3-bit processor would implement binary addition. As an example, consider the following table which depicts the absolute unsigned range of a 3-bit integer.

       0 = 000b
       1 = 001b
       2 = 010b
       3 = 011b
       4 = 100b
       5 = 101b
       6 = 110b
       7 = 111b ---> [Cycles back to 000b on overflow]

    From the above table it is readily apparent that:

       001b(1) + 010b(2) = 011b(3)

    It is also apparent that adding any of these numbers with its numeric complement always yields 2n-1:

       010b(2) + 101b([complement of 2] = 5) = 111b(7) = (23-1)

    Due to the cyclic overflow which occurs when the addition of two n-bit numbers results in an (n+1)-bit result, it therefore follows that adding any of these numbers with its numeric complement + 1 will always yield 0:

       010b(2) + 110b([complement of 2] + 1) = 000b(0)

    Thus we can say that [complement of n] + 1 = -n, so that n + [complement of n] + 1 = n + (-n) = 0. Furthermore, if we now know that n + [complement of n] + 1 = 0, then n + [complement of n - x] + 1 must = n - (n-x) = x.

    Applying this to our original 3-bit table yields:

       0 = 000b = [complement of 0] + 1 = 0
       1 = 001b = [complement of 7] + 1 = -7
       2 = 010b = [complement of 6] + 1 = -6
       3 = 011b = [complement of 5] + 1 = -5
       4 = 100b = [complement of 4] + 1 = -4
       5 = 101b = [complement of 3] + 1 = -3
       6 = 110b = [complement of 2] + 1 = -2
       7 = 111b = [complement of 1] + 1 = -1 ---> [Cycles back to 000b on overflow]

    Whether the representational abstraction is positive, negative or a combination of both as implied with signed twos-complement arithmetic, we now have 2n n-bit patterns which can seamlessly serve both positive 0 to 2n-1 and negative 0 to -(2n)-1 ranges as and when required. In point of fact, all modern processors employ just such a system in order to implement common ALU circuitry for both addition and subtraction operations. When a CPU encounters an i1 - i2 subtraction instruction, it internally performs a [complement + 1] operation on i2 and subsequently processes the operands through the addition circuitry in order to compute i1 + [complement of i2] + 1. With the exception of an additional carry/sign XOR-gated overflow flag, both signed and unsigned addition, and by implication subtraction, are each implicit.

    If we apply the above table to the input sequence [-2n-1, 2n-1-1, -2n-1] as presented in Volte's original reply, we are now able to compute the following n-bit differentials:

    diff #1:
       (2n-1-1) - (-2n-1) =
       3 - (-4) = 3 + 4 =
       (-1) = 7 = 111b

    diff #2:
       (-2n-1) - (2n-1-1) =
       (-4) - 3 = (-4) + (5) =
       (-7) = 1 = 001b

    Starting with our seed -2n-1, we are now able to reproduce the original input sequence by applying each of the above differentials sequentially:

       (-2n-1) + (diff #1) =
       (-4) + 7 = 3 =
       2n-1-1

       (2n-1-1) + (diff #2) =
       3 + (-7) = (-4) =
       -2n-1

    You may of course wish to adopt a more philosophical approach to this problem and conjecture as to why 2n cyclically-sequential numbers would require more than 2n cyclically-sequential differentials?

    Taliadon.

提交回复
热议问题