Chapter 3 Chapter 3
13.41 Accumulating Results: Factorials
Actually,
quadratic. pydid not need to use the math library. We could have taken the square root using exponentiation
**·(Can you see how?) Using
math. sqrt
is somewhat more efficient, and it allowed me to illustrate the use of the math library. In general, if your program requires a common mathematical function, the math library is the first place to look. Table 3.2 shows some of the other functions that are available in the math library:
Python mathematics English
. An
approximation of pi.
pl. 7r
e
e
Anapproximation of e.
sqrt (x)
y'X The square root of x.
sin (x)
SlllX
•The sine of x.
cos(x)
cosx The cosine of
x.tan(x)
tanx The tangent of x.
asin (x)
arCSlllX
•The inverse of sine x.
acos (x)
arccosx The inverse of cosine x.
atan (x)
arctanx The inverse of tangent x.
log(x)
lnx The natural (base e) logarithm of x.
log10(x)
log
10 x The common (base 10) logarithm of x.
exp(x)
ex The exponential of x.
ceil(x)
fxl The smallest whole number>= x.
floor (x)
LxJ The largest whole number < = x.
Table 3.2: Some math library functions
3.4. Accumulating Results: Factorials
Let's write a program that will compute the factorial of a number entered by the user. The basic outline of our program follows an input, process, output pattern:
Input number to take factorial of, n Compute factorial of n, fact
Output fact
Obviously, the tricky part here is in the second step.
How do we actually compute the factorial? Let's try one by hand to get an idea for the process. In computing the factorial of 6, we first multiply 6(5) = 30.
Then we take that result and do another multiplication: 30(4) = 120. This result is multiplied by 3: 120(3) = 360. Finally, this result is multiplied by 2:
360(2) = 720. According to the definition, we then multiply this result by 1, but that won't change the final value of 720.
Now let's try to think about the algorithm more generally. What is actually going on here? We are doing repeated multiplications, and as we go along, we keep track of the running product. This is a very common algorithmic pattern called an accumulator. We build up, or accumulate, a final value piece by piece.
To accomplish this in a program, we will use an accumulator variable and a loop structure. The general pattern looks like this:
Initialize the accumulator variable Loop until final result is reached
update the value of accumulator variable
Realizing this is the pattern that solves the factorial problem, we just need to fill in the details. We will be accumulating the factorial. Let's keep it in a variable called
fact.Each time through the loop, we need to multiply
factby one of the factors
n,(
n-1), ... , 1. It looks like we should use a
forloop that iterates over this sequence of factors. For example, to compute the factorial of 6, we need a loop that works like this:
fact = 1
for factor in [6,5,4,3,2,1]:
fact = fact * factor
Take a minute to trace through the execution of this loop and convince your
self that it works. When the loop body first executes,
facthas the value
1and
factor
is
6.So the new value of
factis 1
*6 = 6. The next time through the
69
loop,
factorwill be
5,and
factis updated to 6
*5
=30. The pattern continues for each successive factor until the final result of 720 has been accumulated.
The initial assignment of
1to
factbefore the loop is essential to get the loop started. Each time through the loop body (including the first), the current value of
factis used to compute the next value. The initialization ensures that
fact
has a value on the very first iteration. Whenever you use the accumulator pattern, make sure you include the proper initialization. Forgetting this is a common mistake of beginning programmers.
Of course, there are many other ways we could have written this loop. As you know from math class, multiplication is commutative and associative, so it really doesn't matter what order we do the multiplications in. We could just as easily go the other direction. You might also notice that including
1in the list of factors is unnecessary, since multiplication by 1 does not change the result.
Here is another version that computes the same result:
fact = 1
for factor in [2,3,4,5,6]:
fact = fact * factor
Unfortunately, neither of these loops solves the original problem. We have hand -coded the list of factors to compute the factorial of 6. What we really want is a program that can compute the factorial of any given input
n.We need some way to generate an appropriate sequence of factors from the value of
n.Luckily, this is quite easy to do using the Python
rangefunction. Recall that
range (n)
produces a sequence of numbers starting with 0 and continuing up to, but not including,
n.There are other variations of
rangethat can be used to produce different sequences. With two parameters,
range (start ,n)produces a sequence that starts with the value
startand continues up to, but does not include,
n.A third version
range (start, n, step)is like the two-parameter version, except that it uses
stepas the increment between numbers. Here are some examples:
>>> list (range (10) )
[0' 1' 2' 3' 4' 5' 6' 7' 8' 9]
>>> list (range (5,10) ) [5' 6' 7' 8' 9]
>>> list (range (5, 10, 3) ) [5, 8]
3.5. Limitations of Computer Arithmetic
Given our input value
n,we have a couple of different
rangecommands that produce an appropriate list of factors for computing the factorial of
n.To generate them from smallest to largest (a Ia our second loop), we could use
range (2 ,n+1).
Notice how I used
n+1as the second parameter, since the range will go up to but not include this value. We need the +1 to make sure that
nitself is included as the last factor.
Another possibility is to generate the factors in the other direction (a Ia our first loop) using the three-parameter version of range and a negative step to cause the counting to go backwards:
range (n, 1, -1).This one produces a list starting with nand counting down (step -1) to, but not including
1.Here then is one possible version of the factorial program:
# factorial. py
# Program to compute the factorial of a number
# Illustrates for loop with an accumulator def main () :
n = int (input ("Please enter a whole number: ") ) fact = 1
for factor in range (n,1,-1) : fact = fact * factor
print ("The factorial of", n, "is", fact) main ()