Computers vs. Calculators Case Study: Learning to Manipulate Fractions
Kirby Urner, Feb 5, 2001 Oregon Curriculum Network
Abstract: Whereas fractions-capable calculators hide the details of implementation, insulating the student from the inner workings of the methods we use to manipulate fractions, a computer-savvy approach may be developed which (a) gives us a fractions-capable CLI (command line environment) and (b) reinforces student understanding of lcm, gcd, primes, composites and other relevant concepts central to the manipulation of fractions.
Whereas some calculators will operate with fractions in p/q format, "saving" kids from needing to learn the concepts (I think we all agree they should not be so saved), with a computer we can more easily _program_ fractions, thereby implementing the very concepts we want kids to get, use and appreciate.
For example, when adding a/b + d/e, I need to get a common denominator. The lowest such denominator will be the lcm of b and e. After I get my result: [a*f + d*g]/lcm where f = lcm/b and g = lcm/e, I'll want to see if I can reduce the result to lowest terms -- which involves finding the gcd.
Example: 2/3 + 5/2 lcm(3,2)=6 f = 6/3 = 2 and g = 6/2 = 3. So we're going (2/3)(2/2) + (5/2)(3/3) i.e. (4/6) + (15/6) = (2f + 5g)/lcm or 19/6. Since gcd(19,6) = 1, no further reducing takes place -- we may want to say that's 3 1/6, but to my eye, 19/6 is terminal (a final answer).
Now let's see this on a computer (>>> is the prompt, at which the student types, with the computer responding flush left):
>>> from functions import Fraction >>> f1 = Fraction(2,3) >>> f2 = Fraction(5,2) >>> f3 = f1 + f2 >>> f3 19/6
That's not so different from doing it on a fractions-capable calculator. The difference comes next, when we pull up source code and start looking at what goes on under the hood:
Ah so... a Fraction object has a numerator and denominator, stored in self.p and self.q respectively. Here we see an algorithm for simplifying:
divisor = gcd(p,q) if |divisor| > 1 p = p/divisor q = q/divisor
So how is the gcd computed? That leads to an interesting topic, not mentioned in the California Standard I don't think: Euclid's Algorithm, one of the oldest examples of an algorithm on the books (shouldn't have been dropped):
def gcd(a,b): """Return greatest common divisor using Euclid's Algorithm.""" while b: a, b = b, a % b return a
Pretty simple. We keep cycling as long as b>0. a % b gives the remainder r when a is divided by b. BTW, kids need exposure to % or mod -- however symbolized -- "that which gives the remainder after division". It's basic to math and a primitive operation in most computer languages -- and I presume a key on most calculators. There's no reason to postpone playing with it until college or Algebra II. If a mod 2 = 0, then a is even -- something to start with.
If b doesn't go evenly into a (without remainder), then the gcd will have to divide both b and the remainder, so now we're looking for gcd(b,r). We just keep cycling until there's no more remainder, at which point the value behind 'a' may be 1 (i.e. no common factors other than 1, meaning a,b were relatively prime).
And what's the relationship between gcd and lcm? That's simple too: lcm(a,b) = a*b/gcd(a,b). You can think of this as getting all the prime factors of both a and b and putting those in the numerator, then canceling any factors they have in common (i.e. the gcd) -- the result being the lowest number into which both a's and b's prime factors will divide, i.e. the lcm.
So when we go to add two fractions, what do we do?
def __add__(self,n): # add self to another fraction fract = self.mkfract(n) common = primes.lcm(self.q,fract.q) term1 = self.p * common/self.q term2 = fract.p * common/fract.q return Fraction(term1+term2,common)
This is the same algorithm as specified above i.e. if adding (a/b) + (c/d), I find:
term1 = a * lcm/b and term2 = d * lcm/e
Then (term1 + term2)/lcm is the result I'm looking for, which I'll make sure is reduced to lowest terms.
My use of __add__ means I'm overriding the meaning of the + operator. With regard the Fractions, the + operator will invoke the method shown above. This is another big advantage of computers: I can make the basic operators behave differently depending on context. That's how mathematicians actually think: "to multiply" means whatever we define it to mean vis-a-vis a given set. It's a generic operation, and one that means one thing with respect to Z (integers) and something else with respect to matrices or permutations.
In sum, by studying the methods behind the Fractions class, students will be reinforced in their understanding of gcd, lcm and the methods for adding and reducing fractions. Of course additional methods for multiplying and dividing fractions are also defined within the same class, the complete source code for which is available at my website (or other websites -- many many people have implemented a Fractions class in one way or another, and many more will do so, in math class or on the job).
Thanks to this Fractions class, I'm able to use the rows of Pascal's Triangle (generated by another method) to compute successive Bernoulli numbers, and output them in the form p/q. This isn't the fastest algorithm out there, but it works, and it links to Pascal's Triangle, which is a corner stone in my curriculum, a bridge from mental geometry to mental arithemetic as per: http://www.mathforum.com/epigone/math-learn/pehrornal
That's a nice big fraction -- another shortcoming of calculators is they usually have a hard time with numbers like this, unless augmented by computer software -- in which case we might as well cut the umbilical chord and just use the computer without the calculator.
Note: in 1998 (actually late '97), I launched a "math makeover campaign" in the USA context. Part of the campaign is to bring higher technology into our classrooms. My strategy has been to promote student involvement, as well as teacher participation. For more background reading and exhibits, see: http://www.teleport.com/~pdx4d/makeover0.html