• Aucun résultat trouvé

THE EUCLIDEAN ALGORITHM

The Integers

3.2 THE EUCLIDEAN ALGORITHM

The previous proposition provides us with a particularly fast way of finding the gcd of two integers. We will calculate the gcd of 132 and 55. If we successively apply the division algorithm to obtain

132 = 2 · 55 + 22 55 = 2 · 22 + 11 22 = 2 · 11 + 0, the preceding proposition then tells us that

(132, 55) = (55, 22) = (22, 11) = (11, 0) = 11.

Note that we wisely chose qandras the same qandrobtained by the division algorithm.

The remainders are all positive, and are getting smaller after each successive division. The remainder must eventually reach 0, and the previous remainder must be the gcd. The proof that this always works follows.

3.2 THE EUCLIDEAN ALGORITHM

PROPOSITION 11 (The Euclidean Algorithm.) Let r0=xandr1=ybe integers such that x≥y> 0. If the division algorithm is successively applied to obtain rj=rj⫹1qj⫹1+rj⫹2with 0 < rj⫹2<rj⫹1forj= 0, 1, 2, . . . , n⫺2 and rn⫹1= 0, then (x,y) = rn.

Proof. This follows almost immediately using proposition 10. Let r0=x,r1=y, where x

≥y> 0. We successively apply the division algorithm to obtain r0=r1q1+r2 with 0 ≤r2<r1

r1=r2q2+r3 with 0 ≤r3<r2

. . .

ri⫺2=ri⫺1qi⫺1+ri

. . .

This process must terminate. The remainders form a strictly decreasing sequence of pos-itive integers bounded below by zero. This sequence can certainly have no more than x terms:

r0≥r1>r2> . . . > rn⫺1>rn>rn⫹1= 0.

We must eventually have rn⫹1= 0 for some n, where rnis the last nonzero remainder.

Proposition 10 then tells us that

(x,y) = (r0,r1) = (r1,r2) = . . . = (rn⫺1,rn) = (rn,rn⫹1) = (rn, 0) = rn

and we have the desired result. I

E

XAMPLE

.

Use the Euclidean algorithm to find the gcd of 252 and 198. Successively apply the division algorithm to obtain

252 = 1 · 198 + 54 198 = 3 · 54 + 36

54 = 1 · 36 + 18 36 = 2 · 18 + 0

The last nonzero remainder is 18, so (252, 198) = 18. We can write this process out very quickly as

(252, 198) = (198, 54) = (54, 36) = (36, 18) = (18, 0) = 18.

Java Algorithm Once we know the Euclidean algorithm, writing a method to compute the gcd should be simple. Though the BigInteger class supplies a method to compute the gcd of two BigIntegers, it may be interesting to write our own. Here, we use a static recursive method. Recursion is natural for this algorithm, because if we have positive ints mandnin Java such that m>n, proposition 10 says that (m,n) = (n,m%n). This makes an easy sub-stitution in a recursive call. The recursion is not particularly wasteful in this case since the Euclidean algorithm arrives at the gcd so quickly. The following test program simply asks the user to enter two integers, then computes and displays their gcd (see Figures 3.4a–c).

import java.io.*;

import javax.swing.*;

import java.math.BigInteger;

public class TestGCD {

public static void main(String[] args) {

BigInteger i=new BigInteger(JOptionPane.showInputDialog(“Enter an integer: “));

BigInteger j=new BigInteger(JOptionPane.showInputDialog (“Enter another integer: “));

JOptionPane.showMessageDialog(null,”The gcd of “+i+” and “+j+” is “+gcd(i,j));

System.exit(0);

}

static BigInteger ZERO=new BigInteger(“0”);

//Compute the gcd recursively using the Euclidean algorithm

private static BigInteger gcd(BigInteger first, BigInteger second) { //Make sure both are nonnegative

first=first.abs();

second=second.abs();

//Call the recursive method

return recurseGCD(first,second);

}

private static BigInteger recurseGCD(BigInteger x, BigInteger y) { if (y.equals(ZERO)) return x;

else return recurseGCD(y,x.mod(y));

} }

3.2 The Euclidean Algorithm 79

Figure 3.4 (a)

(b)

(c)

There is a test applet for computing greatest common divisors on the book’s website under the class name TestGCDApplet. It uses the gcd() method supplied with the BigInte-ger class. Figure 3.5 shows a screen shot of a sample run.

The following development will be very useful to us later on, for it will help us solve spe-cial equations called diophantine equations, and congruences. It also reveals something interesting about the gcd. Recall that the gcd of two numbers is the least positive integer that can be expressed as a linear combination of those two numbers; that is,

(x,y) = mx+ny

for some integers mandn. What are the values of mandn? The next proposition shows us exactly how these two quantities can be computed.

PROPOSITION 12(Extended Euclidean Algorithm). Let xandybe positive integers such thatx≥y> 0. Then

(x,y) = snx+tny

Figure 3.5

where the snandtnare defined recursively as

sj=sj⫺2⫺qj⫺1sj⫺1forj= 2, . . . , n s0= 1

s1= 0

tj=tj⫺2⫺qj⫺1tj⫺1forj= 2, . . . , n t0= 0

t1= 1

and the qjandriare as in the Euclidean algorithm.

Rather than produce a proof right away for this, we do an example to clarify what is going on. Suppose we wish to express the gcd of 252 and 198 as a linear combination of 252 and 198. We can apply the Euclidean algorithm, and while keeping track of the quotients and remainders, we shall also compute the two values sjandtjduring the jth step. This is perhaps best done in a table. (See Table 3.3.)

The fourth remainder is the last nonzero remainder, so we need not compute the fifth row in the table. The two numbers desired are 4, and ⫺5; that is,

18 = (252, 198) = 4 · 252 + (⫺5) · 198 Now, we can show a proof to you that this always works.

Proof. First note that (x,y) = rn, where rnis the last nonzero remainder generated in the Euclidean algorithm. If we show then that

rj=sjx+tjy (*)

᭙(for all) j= 0, 1, . . . , k<n, the result then follows by induction. First, note (*) is true whenj= 0, and when j= 1, since

r0= 1 · x+ 0 · y=s0x+t0y, and r1= 0 · x+ 1 · y=s1x+t1y.

3.2 The Euclidean Algorithm 81

Java Algorithm We should write a euclid() method to calculate the values cited in the foregoing theorem. The BigInteger class does not provide such a method, so we will write a BigIntegerMath class to place methods in. The BigInteger class will be used to house many of the methods used in this book. In particular, this class defines a euclid(BigInteger x, BigInteger y) method, which returns an array (say, arr[]) of three BigIntegers. We will set arr[0] to (x,y) = rn(from Proposition 12), arr[1] to sn, and arr[2] to tn. This method is not recursive; an interesting exercise for you is to write it recursively.

import java.math.*;

import java.security.SecureRandom;

import java.util.*;

public class BigIntegerMath {

//Define some BigInteger constants; this is handy for comparisons static final BigInteger ZERO=new BigInteger(“0”);

static final BigInteger ONE=new BigInteger(“1”);

static final BigInteger TWO=new BigInteger(“2”);

static final BigInteger THREE=new BigInteger(“3”);

static final BigInteger FOUR=new BigInteger(“4”);

//A nonrecursive version of euclid. It returns an array answer of 3 BigIntegers //answer[0] is the gcd, answer[1] is the coefficient of a, answer[2] the coeff //of b

public static BigInteger[] euclid(BigInteger a,BigInteger b) throws IllegalArgumentException {

//Throw an exception if either argument is not positive if (a.compareTo(ZERO)<=0||b.compareTo(ZERO)<=0) throw new

IllegalArgumentException(“Euclid requires both arguments to be positive!”);

BigInteger[] answer=new BigInteger[3];

//Set up all the initial table entries

BigInteger r0=new BigInteger(a.toByteArray());

BigInteger r1=new BigInteger(b.toByteArray());

BigInteger s0=new BigInteger(“1”);

BigInteger s1=new BigInteger(“0”);

BigInteger t0=new BigInteger(“0”);

BigInteger t1=new BigInteger(“1”);

BigInteger q1=r0.divide(r1);

BigInteger r2=r0.mod(r1);

BigInteger s2,t2;

//When r2 becomes zero, the previous table entries are the answers while (r2.compareTo(ZERO)>0) {

s2=s0.subtract(q1.multiply(s1)); s0=s1; s1=s2;

t2=t0.subtract(q1.multiply(t1)); t0=t1; t1=t2;

r0=r1; r1=r2; q1=r0.divide(r1); r2=r0.mod(r1);

}

answer[0]=r1; answer[1]=s1; answer[2]=t1;

return answer;

} }

TestEuclidApplet is on the book’s website. Run it to test the algorithm (see Figure 3.6).