• Tidak ada hasil yang ditemukan

Accumulating Results: Factorials

Chapter 3 Chapter 3

13.41 Accumulating Results: Factorials

Actually,

quadratic. py

did 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

An

approximation 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

1

0 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

fact

by one of the factors

n,

(

n-

1), ... , 1. It looks like we should use a

for

loop 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,

fact

has the value

1

and

factor

is

6.

So the new value of

fact

is 1

*

6 = 6. The next time through the

69

loop,

factor

will be

5,

and

fact

is 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

1

to

fact

before the loop is essential to get the loop started. Each time through the loop body (including the first), the current value of

fact

is 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

1

in 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

range

function. 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

range

that can be used to produce different sequences. With two parameters,

range (start ,n)

produces a sequence that starts with the value

start

and 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

step

as 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

range

commands 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+1

as the second parameter, since the range will go up to but not include this value. We need the +1 to make sure that

n

itself 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 ()

Of course, there are numerous other ways this program could have been written.

I have already mentioned changing the order of factors. Another possibility is to

initialize

fact

to

n

and then use factors starting at

n-

1 (as long as

n

> 0). You

might try out some of these variations and see which one you like best.