|
1 | 1 | # Karatsuba Multiplication
|
2 | 2 |
|
3 |
| -TODO: Explanation/Examples |
| 3 | +Goal: To quickly multiply two numbers together |
4 | 4 |
|
| 5 | +## Long Multiplication |
5 | 6 |
|
| 7 | +In grade school we all learned how to multiply two numbers together via Long Multiplication. So let's try that first! |
6 | 8 |
|
| 9 | +Example 1: Multiply 1234 by 5678 using Long Multiplication |
| 10 | + |
| 11 | + 5678 |
| 12 | + *1234 |
| 13 | + ------ |
| 14 | + 22712 |
| 15 | + 17034- |
| 16 | + 11356-- |
| 17 | + 5678--- |
| 18 | + -------- |
| 19 | + 7006652 |
| 20 | + |
| 21 | +So what's the problem with long multiplication? Speed. Long Multiplication runs in **O(n^2)**. |
| 22 | + |
| 23 | +You can see where the **O(n^2)** comes from in the implementation for Long Multiplication: |
| 24 | + |
| 25 | +```swift |
| 26 | +// Long Multiplication |
| 27 | +func multiply(_ num1: Int, by num2: Int, base: Int = 10) -> Int { |
| 28 | + let num1Array = String(num1).characters.reversed().map{ Int(String($0))! } |
| 29 | + let num2Array = String(num2).characters.reversed().map{ Int(String($0))! } |
| 30 | + |
| 31 | + var product = Array(repeating: 0, count: num1Array.count + num2Array.count) |
| 32 | + |
| 33 | + for i in num1Array.indices { |
| 34 | + var carry = 0 |
| 35 | + for j in num2Array.indices { |
| 36 | + product[i + j] += carry + num1Array[i] * num2Array[j] |
| 37 | + carry = product[i + j] / base |
| 38 | + product[i + j] %= base |
| 39 | + } |
| 40 | + product[i + num2Array.count] += carry |
| 41 | + } |
| 42 | + |
| 43 | + return Int(product.reversed().map{ String($0) }.reduce("", +))! |
| 44 | +} |
| 45 | +``` |
| 46 | + |
| 47 | +The double for loop is the culprit! So Long Multiplication might not be the best algorithm after all. Can we do better? |
| 48 | + |
| 49 | +## Karatsuba Multiplication |
| 50 | + |
| 51 | +The Karatsuba Algorithm was discovered by Anatoly Karatsuba and published in 1962. Karatsuba discovered that you could compute the product of two large numbers using three smaller products and some addition and subtraction. |
| 52 | + |
| 53 | +For two numbers x, y, where m <= n: |
| 54 | + |
| 55 | + x = a*10^m + b |
| 56 | + y = c*10^m + d |
| 57 | + |
| 58 | +Now, we can say: |
| 59 | + |
| 60 | + x*y = a*c*10^(2m) + (a*d + b*c)*10^(m) + b*d |
| 61 | + |
| 62 | +We can compute this function recursively, and that's what makes Karatsuba Multiplication fast. |
| 63 | + |
| 64 | +```swift |
| 65 | +let ac = karatsuba(a, by: c) |
| 66 | +let bd = karatsuba(b, by: d) |
| 67 | +let adPlusbc = karatsuba(a+b, by: c+d) - ac - bd |
| 68 | +``` |
| 69 | + |
| 70 | +The last recursion is interesting. Normally, you'd think we would have to run four recursions to find the product `x*y` (`a*c`, `a*d`, `b*c`, `b*d`). However, Karatsuba realized that you only need three recursions, and some addition and subtraction. Here's the math: |
| 71 | + |
| 72 | + (a+b)*(c+d) - a*c - b*c = (a*c + a*d + b*c + b*d) - a*c - b*c |
| 73 | + = (a*d + b*c) |
| 74 | + |
| 75 | +Pretty cool, huh? |
| 76 | + |
| 77 | +Here's the full implementation |
| 78 | + |
| 79 | +```swift |
| 80 | +// Karatsuba Multiplication |
| 81 | +func karatsuba(_ num1: Int, by num2: Int) -> Int { |
| 82 | + let num1Array = String(num1).characters |
| 83 | + let num2Array = String(num2).characters |
| 84 | + |
| 85 | + guard num1Array.count > 1 && num2Array.count > 1 else { |
| 86 | + return num1*num2 |
| 87 | + } |
| 88 | + |
| 89 | + let n = max(num1Array.count, num2Array.count) |
| 90 | + let nBy2 = n / 2 |
| 91 | + |
| 92 | + let a = num1 / 10^^nBy2 |
| 93 | + let b = num1 % 10^^nBy2 |
| 94 | + let c = num2 / 10^^nBy2 |
| 95 | + let d = num2 % 10^^nBy2 |
| 96 | + |
| 97 | + let ac = karatsuba(a, by: c) |
| 98 | + let bd = karatsuba(b, by: d) |
| 99 | + let adPlusbc = karatsuba(a+b, by: c+d) - ac - bd |
| 100 | + |
| 101 | + let product = ac * 10^^(2 * nBy2) + adPlusbc * 10^^nBy2 + bd |
| 102 | + |
| 103 | + return product |
| 104 | +} |
| 105 | +``` |
| 106 | + |
| 107 | +The run time for this algorithm is about **O(n^1.56)** which is better than the **O(n^2)** for Long Multiplication. |
| 108 | + |
| 109 | +Example 2: Multiply 1234 by 5678 using Karatsuba Multiplication |
| 110 | + |
| 111 | + m = 2 |
| 112 | + x = 1234 = a*10^2 + b = 12*10^2 + 34 |
| 113 | + y = 5678 = c*10^2 + d = 56*10^2 + 78 |
| 114 | + |
| 115 | + a*c = 672 |
| 116 | + b*d = 2652 |
| 117 | + (a*d + b*c) = 2840 |
| 118 | + |
| 119 | + x*y = 672*10^4 + 2840*10^2 + 2652 |
| 120 | + = 6720000 + 284000 + 2652 |
| 121 | + = 7006652 |
| 122 | + |
| 123 | +## Resources |
| 124 | + |
| 125 | +[Wikipedia] (https://en.wikipedia.org/wiki/Karatsuba_algorithm) |
| 126 | + |
| 127 | +[WolframMathWorld] (http://mathworld.wolfram.com/KaratsubaMultiplication.html) |
7 | 128 |
|
8 | 129 | *Written for Swift Algorithm Club by Richard Ash*
|
0 commit comments