Big integer algorithm [11] Karatsuba multiplication, karatsuba Multiplication
★Introduction
The previous two articles introduced Comba multiplication, and finally mentioned that when the input size is large, the required computing time will increase sharply, because the time complexity of Comba multiplication is still O (n ^ 2 ). To break the O (n ^ 2) limitation in multiplication, we need to look at multiplication from a completely different perspective. In the following multiplication algorithm, the polynomial base expressions f (x) and g (x) of the two big integers x and y are used for representation.
So that f (x) = a * x + B, g (x) = c * x + d, h (x) = f (x) * g (x ). Here, x is equivalent to a base. For example, in decimal format, 123456 can be expressed as 123*100 + 456. Then, x is 100.
★Karatsuba multiplication principle
Since the calculation amount increases with n ^ 2 when the input scale increases, we consider splitting a large problem into several small problems by means of grouping, in this way, it is easier to solve these small-scale problems.
For the product z = x * y of x and y, both x and y can be split into two sections: the left half and right half of x are a and B, respectively, the left half and right half of y are c and d, respectively.
Now consider the product h (x) = f (x) * g (x ):
H (x) = (a * x + B) * (c * x + d)
= A * c * (x ^ 2) + (a * d + B * c) * x + B * d
As you can see, to calculate h (x), we need to calculate a multiplication of four halves, three additions, multiplied by x or multiplied by x ^ 2, which can be achieved through shift, all addition and shift operations share O (n) computing.
If T (n) is the total number of operations required to multiply two n-digit integers, the recursive equations include:
T (n) = 4 * T (n/2) + O (n) WHEN n> 1
T (n) = O (1) WHEN n = 1
After solving this recursive equation, T (n) = O (n ^ 2) is obtained, that is, the time complexity is the same as that of Comba multiplication, and there is no improvement. To reduce the computing complexity, we must reduce the number of multiplication computations.
Note that a * d + B * c can be represented by a * c and B * d: (a + B) * (c + d)-a * c-B * d.
Original formula = (a + B) * (c + d)-a * c-B * d
= A * c + a * d + B * c + B * d-a * c-B * d
= A * d + B * c
The conversion above indicates that a * d + B * c can be calculated by two addition operations, so that the total number of multiplication operations is reduced to three. The new recursive equations are listed as follows:
T (n) = 3 * T (n/2) + O (n) WHEN n> 1
T (n) = O (1) WHEN n = 1
After recursive equations are obtained, T (n) = O (n ^ log3) is obtained. Note that the log here is based on 2 and is approximately calculated. The time complexity is T (n) = O (n ^ 1.585), smaller than the O (n ^ 2) of Comba multiplication.
The above is the principle of multiplication using the divide and conquer method. The above algorithm was proposed by Anatolii Alexeevitch Karatsuba in 1960 and published in 1962. Therefore, it is also called Karatsuba multiplication.
★Implementation
The principle is clear. Now let's sort out the ideas:
1. Split input:
Calculate the split base: B = MIN (x-> used, y-> used)/2
X0 and y0 respectively store the low half of x and y, and x1 and y1 store the high half of x and y respectively.
2. Calculate the three products:
X0y0 = x0 * y0 // recursively call the multiplication bn_mul_bn
X1y1 = x1 * y1
T1 = x0 + x1
X0 = y0 + y1
T1 = t1 * x0
3. Calculation intermediate items:
X0 = x0y0 + x1y1
T1 = t1-x0
4. Calculate the final product:
T1 = t1 * (2 ^ (n * B) // shift B digits left
X1y1 = x1y1 * (2 ^ (2 * B) // shift left by 2 * B digits
T1 = x0y0 + t1
Z = t1 + x1y1 // final result
★Implementation
According to the above idea, the implementation code of Karatsuba multiplication is as follows:
static int bn_mul_karatsuba(bignum *z, const bignum *x, const bignum *y){ int ret; size_t i, B; register bn_digit *pa, *pb, *px, *py; bignum x0[1], x1[1], y0[1], y1[1], t1[1], x0y0[1], x1y1[1]; B = BN_MIN(x->used, y->used); B >>= 1; BN_CHECK(bn_init_size(x0, B)); BN_CHECK(bn_init_size(x1, x->used - B)); BN_CHECK(bn_init_size(y0, B)); BN_CHECK(bn_init_size(y1, y->used - B)); BN_CHECK(bn_init_size(t1, B << 1)); BN_CHECK(bn_init_size(x0y0, B << 1)); BN_CHECK(bn_init_size(x1y1, B << 1)); x0->used = y0->used = B; x1->used = x->used - B; y1->used = y->used - B; px = x->dp; py = y->dp; pa = x0->dp; pb = y0->dp; for(i = 0; i < B; i++) { *pa++ = *px++; *pb++ = *py++; } pa = x1->dp; pb = y1->dp; for(i = B; i < x->used; i++) *pa++ = *px++; for(i = B; i < y->used; i++) *pb++ = *py++; bn_clamp(x0); bn_clamp(y0); BN_CHECK(bn_mul_bn(x0y0, x0, y0)); BN_CHECK(bn_mul_bn(x1y1, x1, y1)); BN_CHECK(bn_add_abs(t1, x0, x1)); BN_CHECK(bn_add_abs(x0, y0, y1)); BN_CHECK(bn_mul_bn(t1, x0, t1)); BN_CHECK(bn_add_abs(x0, x0y0, x1y1)); BN_CHECK(bn_sub_abs(t1, t1, x0)); BN_CHECK(bn_lshd(t1, B)); BN_CHECK(bn_lshd(x1y1, B << 1)); BN_CHECK(bn_add_abs(t1, x0y0, t1)); BN_CHECK(bn_add_abs(z, t1, x1y1));clean: bn_free(x0); bn_free(x1); bn_free(y0); bn_free(y1); bn_free(t1); bn_free(x0y0); bn_free(x1y1); return ret;}
The above Code requires a lot of temporary bignum variables, but since we know the size of each bignum from the very beginning, we use the bn_init_size function to initialize and assign the specified number, avoid re-allocating the memory later, saving time.
The algorithm splits the input x and y into two halves at the beginning, and uses three loops. To improve efficiency, the register keyword is added to the front of the pointer to indicate that these pointer variables should be put into the CPU register during execution to speed up variable access.
The multiplication operation is to call the bn_mul_bn function recursively. This is a calculation function of the signed number multiplication function. Later we will talk about it. When recursive calls reach a critical point, the multiplication calculation directly calls the Comba method for calculation, instead of using Karatsuba for recursion. The function prototype of bn_mul_bn is: int bn_mul_bn (bignum * z, const bignum * x, const bignum * y );
Note that each calculation operation (addition, subtraction, multiplication, and shift) may encounter errors during execution. Therefore, you must add the BN_CHECK macro to perform an error check. Once a function call fails, execute the memory cleanup operation after it is adjusted to clean.
★Split point
Although Karatsuba requires less single-precision multiplication than the Comba Method for multiplication, there is also an O (n) overhead for solving a equations, it is used to calculate the intermediate items and merge the final results, which makes the calculation time required for Karatsuba multiplication to deal with numbers with smaller input. Therefore, in practice, after recursion is calculated to a certain size, we should use the Comba method for calculation. In the bn_mul_bn function, the split point size is 80 (when bn_digit is 32 bit) or 64 (when bn_digit is 64 bit ), when the scale of the two numbers is smaller than the split point, the Comba method should be used to calculate the multiplication. The Karatsuba method is used for Recursive calculation only when the scale of the two numbers is greater than or equal to the split point.
★Summary
Karatsuba is a simple recursive multiplication algorithm that splits the input into two parts. However, for a larger number, you can split the input into three or even four parts. When split into three parts, you can use Toom-Cook 3-way multiplication to reduce the complexity to O (n ^ 1.465 ). When split into four parts, use Toom-Cook 4-way multiplication to further reduce the complexity to O (n ^ 1.404 ). For larger numbers, we can split them into 100 segments and use the fast Fourier transformation. The complexity is close to linear, which is about O (n ^ 1.149 ). It can be seen that the larger the split, the lower the time complexity, but the process of calculating the intermediate items and merging the final results will be more complicated, and the overhead will increase. Therefore, the Split points will increase, for public key encryption, there are not too many integers at the moment, so it is appropriate to use Karatsuba, and more complex recursive multiplication is not required.
In the next article, we will use the Comba method and the Karatsuba method to construct the multiplication of signed numbers.
[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/4445566.html