$ \def\compare{ {\mathrm{compare}} } \def\swap{ {\mathrm{swap}} } \def\sort{ {\mathrm{sort}} } \def\insert{ {\mathrm{insert}} } \def\true{ {\mathrm{true}} } \def\false{ {\mathrm{false}} } \def\BubbleSort{ {\mathrm{BubbleSort}} } \def\SelectionSort{ {\mathrm{SelectionSort}} } \def\Merge{ {\mathrm{Merge}} } \def\MergeSort{ {\mathrm{MergeSort}} } \def\QuickSort{ {\mathrm{QuickSort}} } \def\Split{ {\mathrm{Split}} } \def\Multiply{ {\mathrm{Multiply}} } \def\Add{ {\mathrm{Add}} } $
Midterm 10/07
Idea. Break numbers up into parts
Then:
\[\begin{align*} a b &= (a_1 2^B + a_0)(b_1 2^B + b_0)\\ &= a_1 b_1 2^{2B} + (a_1 b_0 + a_0 b_1) 2^B + a_0 b_0 \end{align*}\]Then:
\[a b = c_2 2^{2B} + (c^* - c_2 - c_0) 2^B + c_0\]Conclusion. Each a multiplication of size $n$ can be computed using $3$ multiplications of size $n/2$ and $O(1)$ addition/subtractions/shifts.
KMult(a, b):
n <- size(a) (= size(b))
if n = 1 then return a*b
a = a1 a0
b = b1 b0
c2 <- KMult(a1, b1)
c0 <- KMult(a0, b0)
c <- KMult(a1 + a0, b1 + b0)
return (c2 << n) + ((c - c2 - c0) << (n/2)) + c0
At depth $k$:
KMult
Total running time:
Can show:
Simplify:
Result. The running time of Karatsuba multiplication is $O(n^{\log 3}) \approx O(n^{1.58})$
Theorem (Harvey and ven der Hoeven, 2019). It is possible to multiply two $n$ bit numbers in time $O(n \log n)$.
See Mathematicians Discover the Perfect Way to Multiply from Quanta Magazine
Main technique: “Fast Fourier Transform,” a divide-and-conquer algorithm
Conditional lower bound (Afshani et al., 2019). Multiplying two $n$ bit numbers requires $\Omega(n \log n)$ time, unless the “network coding conjecture” is false.
Running time of Karatsuba multiplication $T(n)$
KMult(a, b):
n <- size(a) (= size(b))
if n = 1 then return a*b
a = a1 a0
b = b1 b0
c2 <- KMult(a1, b1)
c0 <- KMult(a0, b0)
c <- KMult(a1 + a0, b1 + b0)
return (c2 << n) + ((c - c2 - c0) << (n/2)) + c0
Running time satisfies recurrence relation
\[T(n) = 3 T(n / 2) + O(n)\]Recurrence of this form satisfies $T(n) = O(n^{\log 3})$
General form of recurrences
\[T(n) = a T(n / b) + f(n)\]Interpretation for D&C
The “Master Theorem”
$T(n) = a T(n / b) + f(n)$
Define $c = \log_b a$
Three cases:
If $f(n) = O(n^d)$ for $d < c$ then $T(n) = O(n^c)$
If $f(n) = \Theta(n^c \log^k n)$ then $T(n) = O(n^c \log^{k+1} n)$
If $f(n) = \Omega(n^d)$ for $d > c$, then $T(n) = O(f(n))$
In formal statement we have
In practice, might have
The conclusion of the theorem still holds in this case!
$T(n) = a T(n / b) + f(n)$
KMult(a, b):
n <- size(a) (= size(b))
if n = 1 then return a*b
a = a1 a0
b = b1 b0
c2 <- KMult(a1, b1)
c0 <- KMult(a0, b0)
c <- KMult(a1 + a0, b1 + b0)
return (c2 << n) + ((c - c2 - c0) << (n/2)) + c0
$T(n) = a T(n / b) + f(n)$
BinarySearch(a, val, i, j):
if j = i then return false
if j - i = 1 then return (a[i] = val)
m <- (j + i) / 2
if a[m] > val then
return BinarySearch(a, val, i, m)
else
return BinarySearch(a, val, m, j)
endif
$T(n) = a T(n / b) + f(n)$
MergeSort(a, i, j):
if j - i = 1 then
return
endif
m <- (i + j) / 2
MergeSort(a,i,m)
MergeSort(a,m,j)
Merge(a,i,m,j)
Goal. Pick day $b$ to buy and day $s$ to sell to maximize profit.
Input. Array $a$ of size $n$
Output. Indices $b$ (buy) and $s$ (sell) with $1 \leq b \leq s \leq n$ that maximize profit
Devise a procedure to determine max profit in time $O(n^2)$.
Question. Can we compute maximum profit faster?