- Divides both numbers
- Is the largest non-negative number that does so.
- If m is zero, then the GCD is n.
- Otherwise, replace m with the remainder of n divided by m; replace n with m. Return to step 1.
Sounds a little confusing. The goal of this post is to make sense of this algorithm, and subsequently devise a code in Dr. Racket that carries out this algorithm for any two non-negative integers. Let's do it!
Understanding the Problem
In order to devise a code that calculates the GCD, we have to intuitively understand what the GCD is. Let's start off simple. Take 4 and 6 and feed them through Euclid's algorithm.
- 4 does not equal 0. Condition is false.
- 6 divided by 4 is 1 with a remander of 2. Thus, 4 and 6 becomes 2 and 4. Return to Step 1.
- 2 does not equal 0. Condition is false.
- 4 divided by 2 is 2 with no remainder. Thus, 2 and 4 becomes 0 and 2. Return to Step 1.
- The first integer is 0. Condition is satisfied. Thus, the GCD is 2.
Even without carrying out the math, it makes sense because 2 is the largest number that divides both 4 and 6. We now understand that a working Dr. Racket code must take 2 numbers and find the largest number that divides both of them.
From this, we come up with the contract statement.
; GCD : number number -> number
; Take 2 non-negative integers and find the largest common divisor
Devising a Plan
We will attempt to develop the code step by step.
First, we will write two check-expects, then define GCD according to Euclid's algorithm, and finally test it out using some numbers.
Carrying out the Plan
Let's write two check-expects, the first one being 4 and 6 that we have just calculated.
(check-expect (GCD 4 6) 2)
(check-expect (GCD 12 16) 4)
We now move on to define GCD, which is the tricky part. But recognizing that Euclid's algorithm has 2 conditions, we can expect the definition to use cond.
(define (GCD m n)
(cond
[ ... ]
[ ... ]))
The first condition is fairly simple. if m = 0, then (GCD m n) = n. We have,
(cond
[(equal? m 0) n]
[ ... ])
The second condition is harder to dissect. But recognizing that it sends you back to Step 1, we realize this is a recursive example. Simply put, the definition of the function will encompass the function itself, similar to the palindrome function we learned in class.
(cond
[(equal? m 0) n]
[else
(GCD (remainder n m) m)])
Note that m has been replaced by (remainder n m), which is the remainder of n divided by m. Also, n has been replaced by m. This is all according to Euclid's algorithm.
Putting it all together, we have:
; GCD : number number -> number
; Take 2 non-negative integers and find the largest common divisor
(check-expect (GCD 4 6) 2)
(check-expect (GCD 12 16) 4)
(define (GCD m n)
(cond
[(equal? m 0) n]
[else
(GCD (remainder n m) m)]))
Run it in Dr. Racket, you get Both tests passed!
Run it in Dr. Racket, you get Both tests passed!
Looking Back
The function GCD already passes the two check-expects, but we can further test it with some other numbers.
(GCD 175 600)
(GCD 138 234943)
Dr. Racket produces 25 and 1, respectively, which happen to be the correct answers. We have now successfully devised a working code for Euclid's GCD algorithm. Mission accomplished!