Big integer algorithm [06] absolute value addition, absolute value addition

The previous article briefly explains how shift operations are performed, and finally briefly analyzes the algorithm's time complexity. This article introduces absolute value addition. This algorithm is one of the important modules for building the addition and subtraction of signed numbers. The absolute value calculation algorithm is highly optimized and its time complexity is O (n). However, if it is called by an advanced algorithm, its complexity is easily increased to O (n ^ 2) even O (n ^ 3 ). The absolute value addition only calculates the sum of the absolute values of two big integers: z = | x | + | y |. The absolute value calculation is required first, it is because the addition or subtraction of signed values can be achieved by calculating the sum or difference of the absolute values, and then modifying the symbol bit.

**★Computing Principle**

There is no difference between the absolute value addition of a large integer and the pen addition of a primary school mathematics, but it is only in hexadecimal order. The core operation is to add the same digits from the low position to the high position, and carry the digits to the next position. After all the operations accumulate and import operations are completed, the high position of the result is cleared, and the sign is set to 1 (the absolute value is added, and the result must be a non-negative integer ).

**★Implementation**

The implementation code of absolute value addition is given below. It should be noted that this algorithm uses several macro definitions and is based on key operations. The reason is that in some environments, basic data types include single-precision and double-precision data types. In other environments, only single-precision data types are supported. For example, in a 32-bit system, there are 32-bit single precision shaping and 64-bit Double Precision shaping. In a 64-bit system, there is only 64-bit single precision shaping, and there is no 128-bit Double Precision shaping. In different environments, the core operations are slightly different. With macro definition, you can easily switch between different environments. The working principles of these macro definitions will be detailed later.

int bn_add_abs(bignum *z, const bignum *x, const bignum *y){ int ret; const bignum *tmp; bn_digit *px, *py, *pz; size_t i, max, min, olduse; ADDC_INIT if(x->used > y->used) { max = x->used; min = y->used; tmp = x; } else { max = y->used; min = x->used; tmp = y; } olduse = z->used; z->used = max + 1; BN_CHECK(bn_grow(z, z->used)); px = x->dp; py = y->dp; pz = z->dp; for(i = 0; i < min; i++) { ADDC_CORE px++; py++; pz++; } if(min != max) { for(; i < max; i++) { ADDC_FINAL pz++; } } ADDC_STOP for(i = z->used; i < olduse; i++) *pz++ = 0; z->sign = 1; bn_clamp(z);clean: return ret;}

The first step of the algorithm is to find a positive number with a large number and point the pointer tmp to it. Step 2: increase the precision of the target integer. Set the three alias pointers to the input integer and the output integer dp respectively to improve the memory access efficiency. The third step is to accumulate integers with smaller digits into larger integers through a loop, and store the results in the corresponding digits of the target integer, then, an additional loop and the ADDC_STOP macro are used to define the carry generated by the accumulative pass. Finally, the high position is cleared, the sign bit is set to 1, and the extra digits are compressed to complete the computation.

Related macro definitions:

#ifdef _MSC_VER#define LL(v) (v##ui64)#else#define LL(v) (v##ULL)#endif#define BN_HAVE_LONG_LONG#define BN_MASK0 LL(0xFFFFFFFFFFFFFFFF)#else#define BN_MASK0 0xFFFFFFFFUL#endif

This part defines the corresponding mask to extract some bit of the result.

#ifdef BN_HAVE_LONG_LONG#define ADDC_INIT \bn_udbl rr = 0; \#define ADDC_CORE \rr += (bn_udbl)(*px) + (*py); \*pz = (bn_digit)(rr & BN_MASK0); \rr >>= biL; \#define ADDC_FINAL \rr += (bn_udbl)(tmp->dp[i]); \*pz = (bn_digit)(rr & BN_MASK0); \rr >>= biL; \#define ADDC_STOP \z->dp[max] = (bn_digit)(rr & BN_MASK0); \#else#define ADDC_INIT \bn_digit rr, t, c = 0; \#define ADDC_CORE \t = *px; \t = (t + c) & BN_MASK0; \c = (t < c); \rr = (t + *py) & BN_MASK0; \c += (rr < t); \*pz = rr; \#define ADDC_FINAL \t = tmp->dp[i]; \t = (t + c) & BN_MASK0; \c = (t < c); \*pz = t; \#define ADDC_STOP \z->dp[max] = c; \#endif

This macro definition is the key to the algorithm. First, ADDC_INIT indicates that variables are defined in different environments, and then ADDC_CORE defines how to execute the accumulate operation in different environments, ADDC_FINAL then determines how to perform the carry transfer operation after the accumulation is complete, and ADDC_STOP is used to pass the last carry. The following describes how these macros are executed in two different environments.

A. Single-precision and double-precision variables:

1. ADDC_INIT defines the double-precision type variable rr to store the accumulated results. The reason for the double precision is that the result after the single precision is accumulated may be completely stored using the Double Precision type. A simple mathematical proof is as follows:

If the single precision type is an integer of n digits, the maximum unsigned integer that can be expressed is 2 ^ n-1, and the two largest integers are added. The result is: 2*(2 ^ n-1) = 2 ^ (n + 1)-2. The result is out of the range expressed by the single-precision type. Therefore, at least the double-precision type is required for full representation.

2. in ADDC_CORE, calculate the sum of each bits of x and y, and add them to the carry from the low bits. Then, put the rr and mask BN_MASK0 and extract the base, it is stored on the corresponding digit of the target integer. Finally, the rr variable shifts right to the biL bit to calculate the input result. Remember that rr is double-precision. The lower half of the cumulative result is the standard result, and the higher half is the carry result.

3. in ADDC_FINAL, the remainder digits of multiple integers are added to the carry from the low position, and then the base value is extracted from the result and stored to the corresponding digits of the target integer, finally, rr shifts the biL bit right to calculate the new carry value.

4. The ADDC_STOP macro transmits the last carry to the highest digit of the result. Note that the carry value may be 0 or not 0.

B. Single-precision environment only:

1. The ADDC_INIT macro defines three variables: the accumulated Base result rr, the temporary variable t, and the carry value c.

2. The ADDC_CORE calculation here is a little complicated. Step 1: store a certain bit of x in the temporary variable t. Step 2: Add variable t and carry c from the low position to obtain the Base Value of the result, which is stored in variable t. Note that all variables are of the single precision type. If the result is greater than the range expressed by the single precision number, overflow occurs, which is equivalent to a mod 2 ^ n operation, therefore, the Base Value of the result is obtained. Step 3: Determine whether carry is generated in the previous step. In addition, if the result produces carry, the base value is less than two integers. Therefore, if there is an increment, t <c. The comparison result is 1. Step 4: Calculate the sum of the numbers corresponding to t and the second integer, and store the result in the rr variable. Step 5: Determine whether carry is generated. The principle is the same as step 3. In the last step, the final Base result is sent to the corresponding digit of the target integer.

3. ADDC_FINAL is used to pass the rest of carry, which is the same as the above ADDC_FINAL principle, except that the base and the bitwise are represented by two variables.

4. The ADDC_STOP macro transmits the last carry to the highest digit of the result. Note that the carry value may be 0 or not 0.

The above content looks a bit messy. If you are not familiar with the Data Type of C and do not understand what overflow is, you can first look at the relevant chapter to supplement it.

**★Summary**

For efficiency and convenience of transplantation, the above Code splits the key points and writes them separately. Therefore, the Code does not seem intuitive and is not readable. However, the principle of addition is very simple. As long as you understand the calculation principle, you can still quickly understand it. The next article will introduce the absolute value subtraction.

[Back to the directory of this series]

**Copyright Notice**

Original blog, reproduced must contain this statement, to maintain the integrity of this article, and in the form of hyperlink to indicate the author Starrybird and the original address of this article: http://www.cnblogs.com/starrybird/p/4359221.html