🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 10.2 Computing the Greatest Common Divisor [Theorem 10.6](LiB0081.html#1022) gives us a straightforward way to compute the greatest common divisor of two such integers. We simply find the unique factorizations for the two integers, determine which primes they have in common, and determine the greatest common divisor to be a product whose terms are these common primes, where the power of each prime in the product is the smaller of its orders in the two integers. [Example 10.13](LiB0081.html#1023) illustrated this. Another example follows: Example 10.16**![Start example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)**We have **![End example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)** ![](https://box.kancloud.cn/b9cae4d6546443dd01f72442d8f3a3f6_202x50.jpg) So ![](https://box.kancloud.cn/e9856a977d56c667b5ca22d19beea9fd_353x24.jpg) The problem with the previous technique is that it is not easy to find the unique factorization of an integer. You would have had some difficulty factoring the integers in the previous example if we had not given you the factorization. Now imagine the difficulty if the integers had 25 digits instead of 7. Indeed, noone has ever found a polynomial-time algorithm for determining the factorization of an integer. Next we show a more efficient way to compute the greatest common divisor. ### 10.2.1 Euclid's Algorithm [Theorem 10.1](LiB0081.html#1002) gives us a straightforward method for determining the greatest common divisor of two integers. Example 10.9 illustrates the method. Namely, to find the gcd(*n, m*) we recursively apply the equality in the theorem until *m* = 0, and then we return *n*. This method is called *Euclid's algorithm* because it was developed by Euclid around 300 B.C. The algorithm follows: Algorithm 10.1 **Euclid's Algorithm****![Start example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)**Problem: Compute the greatest common divisor of a positive integer and a nonnegative integer. **![End example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)** Inputs: a positive integer *n* and a nonnegative integer *m*. Outputs: the greatest common divisor of *n* and *m*. ``` int gcd (int n, int m) { if (m == 0) return n else return gcd (m, n mod m); // The C++ code would be n % m. } ``` Example 10.17**![Start example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)**We find the greatest common divisor of the numbers in [Example 10.16](#ch10ex25) using [Algorithm 10.1](#ch10ex26). **![End example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)** gcd(7,276,500,3,185,325) =gcd(3,185,325, 905,850) =gcd(90,5850, 767, 775) =gcd(467,775, 438, 075) =gcd(438,075, 29, 700) =gcd(29,700, 22,275) =gcd(22,275, 7,425) =gcd(7,425, 0) =7,425 It seemed pretty easy for us to compute the greatest common divisor using Euclid's algorithm. Let's analyze Algorithm 10.1 to see just how easy it is. First we need a lemma and a theorem. Lemma 10.1**![Start example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)**If *n* > *m* ≥ 1 and the call gcd(*n, m*) (in [Algorithm 10.1](#ch10ex26)) results in *k* recursive calls where *k* ≥ 1, then **![End example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)** ![](https://box.kancloud.cn/f02cd8c606d738c9ef25e59acb4ee07d_256x21.jpg) where *f k* is the *k*th number in the Fibonacci sequence. Proof: The proof is by induction. Induction base: Suppose the call gcd(*n, m*) results in 1 recursive call. Since *m* ≥ 1 ![](https://box.kancloud.cn/5a3e927c12c24e3cf9319b2802ebb7d1_156x21.jpg) Since *n* > *m*, we have *n* ≥ 2, which means ![](https://box.kancloud.cn/90dca1e07eb48c95fa6be421bdb27ae7_151x20.jpg) Induction hypothesis: Assume the lemma is true if *k* – 1 recursive calls are made. Induction step: Show the lemma is true if *k* ≥ 2 recursive calls are made. We need to show ![](https://box.kancloud.cn/a446a901f31df5c88d11f6d20ebfb212_254x20.jpg) The first recursive call is gcd(*m, n* mod *m*). Since there are *k* recursive calls in all, this call must require *k* – 1 recursive calls. Since *k* ≥ 2, there is at least one more recursive call, which means *n* mod *m* ≥ 1. Therefore, since *m* > *n* mod *m*, the conditions of the induction hypothesis are satisfied, which means ![](https://box.kancloud.cn/bfe18dcf453aa59ab0a2e34ae8d2894f_400x21.jpg) So we've arrived at one of the inequalities we needed to show. Towards showing the other, we have ![](https://box.kancloud.cn/f819a5f398a19837a8c53f87ec0efe83_385x23.jpg) where *q* is the quotient of dividing *n* by *m*. Since *n* > *m*, *q* ≥ 1. Inequality 10.2 and Equality 10.3 therefore imply ![](https://box.kancloud.cn/cfabdd6c96b3e64b149adbf4ebc537de_307x20.jpg) This completes the proof. Theorem 10.8**![Start example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)**(**Lamé**) For every integer *k* ≥ 1 if *n* > *m* ≥ 1 and *m* *fk*, the *k*th number in the Fibonacci sequence, then the call gcd(*n, m*) (in [Algorithm 10.1](#ch10ex26)) results in less than *k* recursive calls. **![End example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)** Proof: The proof follows immediately from the previous lemma. Next we analyze [Algorithm 10.1](#ch10ex26). Recall from [Section 9.2](LiB0075.html#887) that in numeric algorithms, the number(s) that is the input is not the input size. Rather the input size is the number of characters it takes to write the input. If we use binary encoding, the input size is the number of bits it takes to encode the number(s), which is about equal to the lg of the number(s). **![Start Sidebar](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)**Analysis of Algorithm 10.1 Worst-Case Time Complexity (Euclid's Algorithm)![](https://box.kancloud.cn/485bc67a7beadb016ac9d44f235f6e03_27x27.jpg) Basic operation: one bit manipulation in the computation of a remainder. Input size: the number of bits *s* it takes to encode *n* and the number of bits *t* it takes to encode *m*. That is, ![](https://box.kancloud.cn/8817b9d09a994e34d202a3442cdf124a_260x22.jpg) Without loss of generality, we will analyze the case where 1 ≤ *m* < *n*. That is, if *m* = *n*, there will be no recursive calls, while if *m* < *n*, the first recursive call will be gcd(*m, n*), which means the first argument is larger. We will not determine the exact time complexity. Rather we will first show the number of recursive calls *Calls*(*s, t*) is Θ(*t*), and then we will find a bound for the worst-case time complexity. First we show *Calls*(*s, t*) is in *O* (*t*). Assuming *m* ≥ 2, let *ff* be the number in the Fibonacci sequence such that ![](https://box.kancloud.cn/49716d9b9570b4f84ac5ce32d9a4dcaf_356x23.jpg) In Example B.9 in Section B.2.1 we show that ![](https://box.kancloud.cn/2807d813e1c1f8f1f7badb9278a175a8_400x50.jpg) Either *k* – 1 is odd or *k* – 2 is odd. Without loss of generality, assume *k* – 1 is odd. Owing to Equality 10.5 and Inequality 10.4, we have ![](https://box.kancloud.cn/0ceda2a79ed5aff2270f849911a4caeb_400x48.jpg) Owing to Equality 10.4, [Theorem 10.8](#ch10ex29) implies ![](https://box.kancloud.cn/dc92dce25ffb1b0a45bc2f490a59bef7_355x23.jpg) Inequalities 10.6 and 10.7 imply that ![](https://box.kancloud.cn/0892eb8264daa1409fe01e2d461b9a2e_365x21.jpg) It is left as an execise to show that the call gcd(*f**k* +1, *fk*) requires exactly *k* – 1 recursive calls. We conclude that ![](https://box.kancloud.cn/6cee4bd96c7366ef1e39e16a94fe9bcd_152x22.jpg) where *W calls*(*s, t*) is the worst-case number of recursive calls for input size *s, t*. For each recursive call, we compute one remainder. It is left as an exercise to show that, if we use the standard long division algorithm (as discussed in [Section 2.6](LiB0020.html#207)) to compute the remainder, the worst case number of bit manipulations needed to compute *r* = *n* mod *m* for *m* < *n* is bounded above by ![](https://box.kancloud.cn/75aff7ee43d79c1c45cd794de0f0d890_366x23.jpg) where *q* is the quotient of dividing *n* by *m*, and *c* is a constant. We will show if *r* > 0, then, for the input size sufficiently larger, the worst case number of bit manipulations needed to compute *r* is bounded above by ![](https://box.kancloud.cn/865d72ffe2a2d4be9e1a32f1081e49d4_400x21.jpg) To that end, since *q* = (*n* – *r*) /*m* and 1 ≤ *r* < *m*, ![](https://box.kancloud.cn/5f28157a3f6e0321ce40fc9befc9829d_200x164.jpg) This last inequality along with Relation 10.9 establishes Bound 10.10. Owing to this bound, the total number of bit manipulations needed to compute all remainders in all recursive calls is bounded above by ![](https://box.kancloud.cn/f7635e8d565f3c81d0382012dec74e8d_400x82.jpg) Relation 10.8 implies the number of recursive calls is bounded above by *dt*, where *d* is a constant greater than 0. This means the number of terms in Bound 10.11 is bounded above by *dt*. Therefore, since *n* > *m* > *r* > *m* mod *r* > … (where the dots denote the remaining terms in Bound 10.11), we conclude from Bound 10.11 that ![](https://box.kancloud.cn/65c3c5886936b83330f7449ca6bc64ce_128x22.jpg) **![End Sidebar](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)** ### 10.2.2 An Extension to Euclid's Algorithm [Theorem 10.1](LiB0081.html#1002) entails that there are integers *i* and *j* such that ![](https://box.kancloud.cn/aa1055685a6241732b88985a6b350efc_170x22.jpg) Knowledge of these integers will be important to our algorithm for solving modular linear equations in the next section. Next we modify [Algorithm 10.1](#ch10ex26) to also produce these integers. In this version we make gcd a variable because so doing makes the proof of the correctness of the algorithm more transparent. Algorithm 10.2 Euclid's Algorithm 2**![Start example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)**Problem: Compute the greatest common divisor of a positive integer and a nonnegative integer. **![End example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)** Inputs: a positive integer *n* and a nonnegative integer *m*. Outputs: the greatest common divisor *gcd* of *n* and *m*, and integers *i* and *j* such that *gcd*=*in* + *jm*. ``` void Euclid (int n, int m, int& gcd, int& i, int& j) { if (m == 0) { gcd = n; i = 1; j = 0; } else { int i', j', gcd'; Euclid (m, n mod m, gcd', i', j'); // The C++ code would be n% m gcd = gcd’; i = j’; j = i'–[n/m] j'; } } ``` [Algorithm 10.2](#ch10ex30) clearly has the same time complexity as [Algorithm 10.1](#ch10ex26). So we need only prove it is correct. Before doing this, we show an example of applying it. Example 10.18**![Start example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)**[Table 10.1](#ch10table01) illustrates the flow of [Algorithm 10.2](#ch10ex30) when the top-level call is **![End example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)** ![](https://box.kancloud.cn/d9da3e07a2d5bc94f491572cc12a8b29_184x22.jpg) The values returned at the top level are *gcd* = 6, *i* = –2, and *j* = 3. Next we prove [Algorithm 10.2](#ch10ex30) is correct. Table 10.1: The values determined by [Algorithm 10.2](#ch10ex30) when *n* = 42 and *m* = 30. The top-level call is labeled 0; the three recursive calls are labeled 1–3. The arrows show the order in which the values are determined.Call *n* *m* *gcd* *i* *j* ↓ ↓ 0 42 30 6 –2 3 1 30 12 6 1 –2 2 12 6 6 0 1 3 6 0 6 1 0 → → ↑ ↑ ↑ Theorem 10.9**![Start example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)**The values of *i* and *j* returned by [Algorithm 10.2](#ch10ex30) are integers such that **![End example](https://box.kancloud.cn/e95df9d604ab2d89febe370ae4d88fb1_1x1.gif)** ![](https://box.kancloud.cn/823c8b66bdf138ae46cfe97744a216af_170x23.jpg) Proof: The proof is by induction. Induction base: In the last recursive call *m* = 0, which means the gcd(*n*, *m*) = *n*. Since the values of *i* and *j* are assigned values 1 and 0, respectively, in that call, we have that ![](https://box.kancloud.cn/4930d981df5cc5d907210f2eaf83bb47_382x22.jpg) Induction hypothesis: Assume in the *k*th recursive call the values determined for *i* and *j* are such that ![](https://box.kancloud.cn/fd61d8475a05e12dc4286804ae274e12_169x22.jpg) Then the values returned by that call for *i’* and *j’* \[to the (*k* – 1)st recursive call\] are values such that ![](https://box.kancloud.cn/4d0bfed295b9324b006da1486c840b90_286x23.jpg) Induction step: We have for the (*k* – 1)st call that *in* + *mj* = *j’n* + (*i’* – \[*n*/*m*\] *j’*) *m* =*i’m* + *j’* (*n* – \[*n*/*m*\] *m*) =*i’m* + *j’n* mod *m* =gcd(*m*, *n* mod *m*) = gcd(*n*, *m*). The second to the last equality is due to the induction hypothesis, and the last equality is owing to [Theorem 10.3](LiB0081.html#1010). Notice that the value [Algorithm 10.2](#ch10ex30) returns for *j* in the final recursive call can be any integer. We choose 0 for simplicity. Choosing a different integer yields a different (*i*, *j*) pair with the gcd(*n*, *m*) = *in* + *jm*.