|
Let's look at the problem of computing xn, where x and n are integers and n > 0. For example, 24 = 2×2×2×2 = 16.
Since xn = x×x×…×x, repetition seems to be called for.
It is not a good idea to proceed directly to writing C++ code. Instead, we will take an approach called pre-simulation, where we begin by performing a hand simulation of an algorithm that we have in mind.
Think about how you would solve the problem by hand
How would you compute 24 by hand? An obvious approach is to start at 2 and successively multiply by 2 until you have 24. The intermediate results are 2, 4, 8 and 16. |
Now solve one or two examples by hand, in some detail
Computing 34 seems like a reasonable example. But now it is important to begin tying down variables. Start with 3, and successively multiply by 3 a total of 3 times. If the power of 3 is stored in variable p, then p changes as follows. p 3 9 27 81 |
Decide on control variables
It is clear that you need variable p. But that cannot be enough. How do you know when you have the result? When doing the computation by hand, you are keeping a count in your head. That needs to be brought out into the open. Another variable, k, is called for; it tells the power of 3 stored in variable p. p k x n 3 1 3 4 (p = x1) 9 2 (p = x2) 27 3 (p = x3) 81 4 (p = x4) |
Write the pieces of the loop based on the pre-simulation
Examining the pre-simulation, initialization of
p and k should clearly be
p = x; k = 1;The following statements serve to update p and k. p = p * x; k = k + 1; |
Decide when to end the loop
How can we recognize the last line of the pre-simulation, where p is the answer? What makes it different from the other lines? Clearly, k = n. The loop should keep going as long as k ≠ n. |
Put the pieces together
Here is a definition of function power(x, n) based
on that plan.
// power(x,n) returns x to the n-th power. // // Requirement: n > 0. int power(int x, int n) { int k = 1; int p = x; while(k != n) { p = p * x; k = k + 1; } return p; } |
Check your work with a hand simulation of what you wrote.
The loop that you wrote should give exactly
the same hand simulation as the pre-simulation. Here
is the entire simulation for x = 3 and n = 4.
p k n 3 1 4 9 2 27 3 81 4 |
Suppose that x and y are two nonnegative integers, not both 0. The greatest common divisor gcd(x, y) of x and y is the largest integer that is a divisor (or factor) of x and y. For example, gcd(15, 40) = 5.
Long ago, Euclid determined the following facts, where x mod y is the remainder when you divide x by y. (It is written x % y in C++).
gcd(x, 0) | = | x | (x ≠ 0) |
gcd(x, y) | = | gcd(y, x mod y) | (y ≠ 0) |
Let's plan and write function gcd(x, y).
Try an example by hand
You can compute gcd(15, 40) by hand using Euclid's equations.
|
Decide on control variables and do a pre-simulation
At each step, there are two numbers, the two parameters
of gcd in Euclid's equations. Let's call
those two numbers m and n.
A pre-simulation of gcd(15, 40), where x = 15 and y = 40, looks similar to the idea above, but shows more detail. m n x y 15 40 15 40 40 15 15 10 10 5 5 0 |
Write the pieces of a loop based on the pre-simulation
The initialization should be clear.
m = x; n = y;How should m and n be updated? Notice that it will not work to say m = y; n = x;That correctly produces the second line for the special case where x = 15 and y = 40. But it does not work to produce subsequent lines, and does not even produce the second line correctly when x = 40 and y = 15. We need code that updates m and n correctly regardless of their values (as long as n > 0). But, as long as we are careful to think in general terms, looking at the first two lines should lead us to reasonable update code. Let's try the following, based on Euclid's equations. m = n; n = m % n;The first two lines of the pre-simulation above are as follows. m n x y 15 40 15 40 40 15Now let's do a careful hand simulation the proposed update code to see whether it produces the next line of the simulation correctly. The starting point is the first line. m n 15 40The first statement m = n; of the proposed update code, m = n; n = m % n;stores the value of n into m, replacing the former value of m. m n 40 40The second statement stores 40 % 40, which is 0, into n. m n 40 0That does not match the desired pre-simulation, so we need to change the update code. Would it work to write the statements in the opposite order? n = m % n; m = n;That still does not work. Let's write m0 and n0 for the values of m and n in the first line, and write m1 and n1 for the values of m and n in the second line of the pre-simulation. Then n1 = m0 % n0; m1 = n0;Now the issue is clear. The updated value m1 of m depends on the old value n0 and the updated value n1 of n depends one the old value m0. One way to fix the update code is to remember the old values of m and n before changing m and n. int oldm = m; int oldn = n; m = oldn; n = oldm % oldn;That works. (Do a hand simulation of it to show that it correctly updates m and n.) |
Decide when to end the loop
The loop should continue as long as n > 0. Euclid tells us that gcd(m, 0) = m, so when n = 0, the loop should stop; the result is m. |
Put the pieces together
int gcd(int x, int y) { int m = x; int n = y; while(n != 0) { int oldm = m; int oldn = n; m = oldn; n = oldm % oldn; } return m; } |
Suppose that n is a positive integer. A proper divisior of n is an integer k where 0 < k < n and k is a divisor (or factor) of n. For example, 2 is a proper divisor of 6. Notice that, if 0 < k < n, you can tell whether k is a proper divisor of n by testing whether n%k == 0.
Say that n is perfect if n is equal to the sum of all of its proper divisors. For example, 6 is perfect because the proper divisors of 6 are 1, 2 and 3 and 1 + 2 + 3 = 6.
Write a definition of function isPerfect(n), which returns true if n is perfect. Plan the loop before starting to code.
Answer
|