Beruflich Dokumente
Kultur Dokumente
1 Simple Multiplication
The simplest algorithm for multiplying integers a and b is to simply add b to 0 exactly a times.
Algorithm product(a,b)
Input: a ≥ 0 and b ≥ 0 are integers.
Output: the product of a and b.
r← 0
for i ← 1 to a do
r ← r+b
return r
Can you determine the number of additions that the algorithm uses to find the product of a and
b? It shouldn’t be too difficult to see that it uses a additions. Can we use fewer? Notice that when
a > b, product(b,a) uses b additions whereas product(a,b) uses a which is greater than b additions. The
following algorithm makes sure that we always use min(a, b) additions:
Algorithm product(a,b)
Input: a ≥ 0 and b ≥ 0 are integers.
Output: the product of a and b.
if a > b then
t← a
a← b
b← t
r← 0
for i ← 1 to a do
r ← r+b
return r
This is certainly better than before. From now on we’ll assume that a ≤ b.
2 Recursive Multiplication
We still might be able to improve efficiency by redefining multiplication recursively, i.e. like this:
(
0 if a = 0
a×b=
b + (a − 1) × b otherwise
This definition is recursive because we use multiplication to define multiplication. Though this is circular,
we’ll soon see that it is not useless. Below is the pseudocode corresponding to this definition:
Algorithm product(a,b)
Input: b ≥ a ≥ 0 are integers.
Output: the product of a and b.
if a = 0 then
return 0
else
return b + product(a − 1, b)
Just like the definition, the algorithm product is recursive since it calls itself. The previous algorithms
are not recursive, we call them iterative. To understand how this algorithm works, consider the example
multiplying 3 and 5:
Therefore:
1. product(1,5) returns 5 + 0 = 5,
As you can see, having the algorithm call itself is not a problem because it calls itself with a smaller a each
time. Eventually, we have a = 0 in which case the algorithm does not call itself.
3 Fast Multiplication
Unfortunately, this algorithm is no more efficient than the algorithms before. We have not, however,
exhausted the different ways to define multiplication recursively so we try another definition:
0
if a = 0
a×b= 2b a2 if a > 0 is even
b + 2b a−1
2
otherwise
j k j k j k j k j k j k
11
= 5 92 = 4 72 = 3 52 = 2 32 = 1 12 = 0
j2k j k j k j k j k j k
10
2
= 5 82 = 4 62 = 3 42 = 2 22 = 1 02 = 0
To see how this algorithm works, consider using it to multiply 10 and 16.
Therefore:
All together, the algorithm used 6 additions, much less than 10, the number of additions the previous
algorithms would have used.
One of the requirements that we stated when we started designing multiplication algorithms was that
we only use addition. However, you may have noticed that the previous algorithm uses division by 2
and a test for determining whether or not an integer is even. It turns out that computers can do both
of these operations very quickly. Suppose that the binary representation of a stored by the computer is
ak ak−1 . . . a1 a0 for some k ≥ 0 i.e. each ai = 0 or 1. Thus, we have
1. product(x,y) calls
j k
x
2. product( 2
,y) which calls
b x2 c
3. product( 2
,y) which calls
b2c
x
2
4. product( 2
,y) which calls
Notice that the algorithm uses at most 2(i − 1) additions to calculate the product of x and y because each
call except the ith listed above accounts for either one addition if a is even or two if a is odd. Suppose that
the binary representation of x is xk xk−1 . . . x0 with xk = 1. From our discussion above, we have:
b x2 c
3. the binary representation of 2
is xk xk−1 . . . x2 ;
b2c
x
2
4. the binary representation of 2
is xk xk−1 . . . x3 ;
... and
i-1. the binary representation of 1 is xk ;
i. the binary representation of 0 is 0.
Thus, i is at most k + 2, so the algorithm uses at most 2(i − 1) ≤ 2(k + 2 − 1) = 2k + 2 additions. Since
the binary representation of x is xk xk−1 . . . x0 , we have
x = xk 2k + xk−1 2k−1 + . . . + x1 21 + x0 20 .
Since xk = 1, we have
x ≥ xk 2k = 2k .
Since logm (n) = p if and only if n = mp , we then have
log2 (x) ≥ k.
x 2 log2 (x) + 2
8 8
9 8.3
10 8.6
11 8.9
12 9.2
13 9.4
14 9.6
15 9.8
16 10
32 12
64 14
128 16
256 18
512 20
1024 22
2048 24
4096 26
8192 28
16384 30
32768 32
The last row is fairly dramatic! Rather than use 32,768 additions, the algorithm uses only 32.
4 Running Time
When we design algorithms, what we’re really interested in is how quickly the algorithm can complete its
assigned task. After all, we use computers to save ourselves time, so it is extremely important that they
complete tasks quickly. For example, would you continue to use a word processor to write papers if every
time you pressed a key it took 20 seconds for the corresponding character to appear on the screen? Would
you use the search-and-replace function if it took 2 minutes for to search through your 5-page paper?
One way to compare algorithms, is to implement them in some programming language and then execute
them on a computer, timing each one to see which is fastest. There are several limitations to this method:
1. How quickly a program completes a task, depends on more than just its underlying algorithm. It
depends on the speed of the machine on which it is running, the operating system in which it is
running, decisions the programmer made when designing the program, and so on.
2. Algorithms cannot be compared until they are implemented and tested. It would be much better
to be able to predict whether or not an algorithm will be efficient before we implement it to avoid
implementing innefficient algorithms.
3. A finite set of tests do not tell the whole story. For many algorithms, the number of possible tests
is too large to try them all. As a result, when testing a program, we may accidently (or purposely)
avoid tests that show that the program is very slow.
In this lecture, we compared algorithms by comparing the number of additions that each uses. This
method, however, may not be useful for comparing algorithms that do not use addition. Consequently,
we should count all operations used by an algorithm. Later in the course we will define a set of primitive
operations including assignment, addition and integer comparison on which we will design all algorithms
so that we can compare them.