Multiplication Algorithms
Explore the foundational concepts of multiplication algorithms, including lattice and peasant multiplication, and an ancient geometric approach using compass and straightedge. Understand their histories, implementations, and efficiencies, to strengthen your algorithmic problem-solving skills in Python.
We'll cover the following...
Historical roots of algorithms
Although they have been a topic of formal academic study for only a few decades, algorithms have been with us since the dawn of civilization. Descriptions of step-by-step arithmetic computation are among the earliest examples of written human language, long predating the expositions by Fibonacci and al-Khwarizmi or even the place value notation they popularized.
Lattice multiplication
The most familiar method for multiplying large numbers, at least for American students, is the lattice algorithm. This algorithm was popularized by Fibonacci in Liber Abaci—which he learned from Arabic sources including al-Khwarizmi, who in turn learned it from Indian sources including Brahmagupta’s 7th-century treatise Brahmasphutasiddhanta, who may have learned it from Chinese sources. The oldest surviving descriptions of the algorithm appear in The Mathematical Classic of Sunzi, written in China between the 3rd and 5th centuries, and in Eutocius of Ascalon’s commentaries on Archimedes’ Measurement of the Circle, written around 500 CE, but there is evidence that the algorithm was known much earlier. Eutocius credits the method to a lost treatise of Apollonius of Perga, who lived around 300 BCE, entitled Okytokion. The Sumerians recorded multiplication tables on clay tablets as early as 2600 BCE, suggesting that they may have used the lattice algorithm.
The lattice algorithm assumes that the input numbers are represented as explicit strings of digits; we’ll assume here that we’re working in base ten, but the algorithm generalizes immediately to any other base. To simplify notation, the input consists of a pair of arrays and , representing the numbers
and similarly, the output consists of a single array , representing the product
The algorithm uses addition and single-digit multiplication as primitive operations. Addition can be performed using a simple for loop. In practice, single-digit multiplication is performed using a lookup table, either carved into clay tablets, painted on strips of wood or bamboo, written on paper, stored in read-only memory, or memorized by the computator. The entire lattice algorithm can be summarized by the formula
Different variants of the lattice algorithm evaluate the partial products in different orders and use different strategies for computing their sum. For example, in Liber Abaci, Fibonacci describes a variant that considers the partial products in increasing order of significance, as shown in modern pseudocode below:
Algorithm
Implementation
Explanation
-
Lines 2–3: We calculate the lengths of input vectors
XandYand assign them to variablesmandn. -
Lines 6–12: We check if the index
jis valid (i.e., if it is within the bounds of the listY) and if the sum ofiandjis equal tok. If both conditions aretrue, the code multiplies the coefficient ofXat indexiwith the coefficient ofYat indexjand adds the result to a variable hold. -
Lines 11–12: The code stores the last digit of hold in the -th position of
Zand updates hold to hold the quotient of the previous hold value divided by 10. -
Lines 14–15: It removes any trailing zeros from the
Zlist. -
Lines 20–28: It creates two input vectors
XandY, calls thefibonacci_multiplyfunction with these vectors as arguments, and prints the result.
Fibonacci’s algorithm is often executed by storing all the partial products in a two-dimensional table (often called a tableau, grate, or lattice) and then summing along the diagonals with appropriate carries. American elementary-school students are taught to multiply one factor (the multiplicand) by each digit in the other factor (the multiplier), writing down all the multiplicand-by-digit products before adding them up. This was also the method described by Eutocius, although he fittingly considered the multiplier digits from left to right. Both of these variants (and several others) are described and illustrated side by side in the anonymous 1458 textbook L’Arte dell’Abbaco, also known as the Treviso Arithmetic, the first printed mathematics book in the West.
All of these variants of the lattice algorithm and other similar variants described by Sunzi, al-Khwarizmi, Fibonacci, L’Arte dell’Abbaco, and many other sources compute the product of any -digit number and any -digit number in time.The running time of every variant is dominated by the number of single-digit multiplications.
Duplation and mediation
The lattice algorithm is not the oldest multiplication algorithm for which we have direct recorded evidence. An even older and arguably simpler algorithm, which does not rely on place-value notation, is sometimes called Russian peasant multiplication, Ethiopian peasant multiplication, or just peasant multiplication. A variant of this algorithm was copied into the Rhind papyrus by the Egyptian scribe Ahmes around 1650 BCE, from a document he claimed was (then) about 350 years old. This algorithm was still taught in elementary schools in Eastern Europe in the late 20th century; it was also commonly used by early digital computers that did not implement integer multiplication directly in the hardware.
The peasant multiplication algorithm reduces the difficult task of multiplying arbitrary numbers to a sequence of four simpler operations: (1) determining parity (even or odd), (2) addition, (3) duplation (doubling a number), and (4) mediation (halving a number, rounding down).
Algortihm
Implementation
Explanation
-
Lines 3–5: We start a loop that continues until
xbecomes0. The code checks if the current value ofxis odd. If it is, the following block of code is executed, and the value ofyis added to theprodvariable. This step simulates the doubling and halving process of the peasant multiplication algorithm. -
Line 13: The code calls the
peasant_multiplyfunction with the values ofxandyas arguments. The returned product is stored in theprodvariable.
The correctness of this algorithm follows by induction from the following recursive identity, which holds for all non-negative integers and :
Arguably, this recurrence can be seen as the peasant multiplication algorithm. Don’t let the iterative pseudocode fool you; the algorithm is fundamentally recursive!
As stated, performs parity, addition, and mediation operations, but we can improve this bound to by swapping the two arguments when . Assuming the numbers are represented using any reasonable place-value notation (like binary, decimal, Babylonian hexagesimal, Egyptian duodecimal, Roman numeral, Chinese counting rods, bead positions on an abacus, and so on), each operation requires at most single-digit operations, so the overall running time of the algorithm is
In other words, this algorithm requires time to multiply an -digit number by an -digit number; up to constant factors, this is the same running time as the lattice algorithm. This algorithm requires more paperwork to execute by hand than the lattice algorithm (a constant factor!), but the necessary primitive operations are arguably easier for humans to perform. In fact, the two algorithms are equivalent when numbers are represented in binary.
Compass and straightedge
Classical Greek geometers identified numbers (or, more accurately, magnitudes) with line segments of the appropriate length, which they manipulated using two simple mechanical tools—the compass and the straightedge—versions of which had already been in common use by surveyors, architects, and other artisans for centuries. Using only these two tools, these scholars reduced several complex geometric constructions to the following primitive operations, starting with one or more identified reference points.
- Draw the unique line passing through two distinct identified points.
- Draw the unique circle centered at one identified point and passing through another.
- Identify the intersection point (if any) of two lines.
- Identify the intersection points (if any) of a line and a circle.
- Identify the intersection points (if any) of two circles.
In practice, Greek geometry students almost certainly drew their constructions on an abax, a table covered in dust or sand. Centuries earlier, Egyptian surveyors carried out many of the same constructions using ropes to determine straight lines and circles on the ground. However, Euclid and other Greek geometers presented compass and straightedge constructions as precise mathematical abstractions—points are ideal points, lines are ideal lines, and circles are ideal circles.
The below illustration shows an algorithm, described in Euclid’s Elements about 2500 years ago, for multiplying or dividing two magnitudes. The input consists of four distinct points , , , and , and the goal is to construct a point such that . In particular, if we define to be our unit of length, then the algorithm computes the product of and . Notice that Euclid first defines a new primitive operation RightAngle by (as modern programmers would phrase it) writing a subroutine. The correctness of the algorithm follows from the observation that triangles and are similar. The second and third lines of the main algorithm are ambiguous, because intersects any circle centered at at two distinct points, but the algorithm is actually correct no matter which intersection points are chosen for and .
Algorithm
Construct the line perpendicular to l passing through P.
Construct a point Z such that |AZ| = |AC||AD|/|AB|.
Euclid’s algorithm reduces the problem of multiplying two magnitudes (lengths) to a series of primitive compass and straightedge operations. These operations are difficult to implement precisely on a modern digital computer, but Euclid’s algorithm wasn’t designed for a digital computer. It was designed for the Platonic ideal geometer, wielding the Platonic ideal compass and the Platonic ideal straightedge, who could execute each operation perfectly in constant time by definition. In this model of computation, runs in time.