chap 1-2 数论算法-乘除法
1. $n-bit$乘法的原理与实现
小学的时候就学过乘法的竖式计算,二进制乘法步骤如下:
1 | 1 1 0 1 (13) |
计算机硬件里乘法器的原理也是类似:
总结就是:$A$乘以$B$的第$k$位然后左移$k$位,作为部分积,最后累加所有部分积。这样做是否正确?
$Proof:$ 假设$N$和$M$是两个乘数,$M$为$k-bit$二进制整数,每一位为$b_k$,$M$可以被写做$M=b_0+2b_1+2^2b_2+\cdots +2^kb_k$。那么,$N\cdot M=Nb_0+2Nb_1+2^2Nb_2+\cdots +2^kNb_k$,这符合上述步骤的结果。
该算法的复杂度是多少?观察竖式,每生成一行部分积,复杂度为$O(n)$;最后要进行$n-1$次部分积求和,故总复杂度为$O(n^2)$。
换一种视角看待乘法,我们其实可以用递归的形式来表达上述步骤:
$$
\begin{equation}
x\cdot y=
\begin{cases}
2(x\cdot \lfloor\frac{y}{2}\rfloor), & y为偶数 \\ x+2(x\cdot \lfloor\frac{y}{2}\rfloor), & y为奇数
\end{cases}
\end{equation}
$$
$Proof:$ 若$y=2k$,则$2(x\cdot \lfloor\frac{y}{2}\rfloor)=2xk=xy$;若$y=2k+1$,则$x+2(x\cdot \lfloor\frac{y}{2}\rfloor)=x(2k+1)=xy$。▮
递归表达式中,除以2的操作就是右移,乘以2的操作就是左移。本质上与竖式计算相同,只不过竖式计算是自上而下累加部分积,这里是自下而上累加部分积。
利用递归形式,我们可以很容易写出伪代码:
1 | function multiply(x, y){ |
具体实现:
1 | Binary multiply(const Binary& x, const Binary& y) { |
测试结果:
1 | multiplication_test |
该递归算法的复杂度是多少?首先计算递归调用的次数,每次将$y$右移1位,所以总共调用$n$次,每次执行的复杂度为$O(n)$,故总复杂度仍然为$O(n^2)$。
是否存在更好的方法?确实存在,之后会详细介绍。
2. $n-bit$除法的原理与实现
假设$x/y$,除法的本质就是找到商$q$和余数$r$,使$x=qy+r$,其中$r<y$。
继续采用递归的形式实现算法:
假设$\lfloor \frac{x}{2}\rfloor / y = (q, r)$,$x=2k$且$2r<y$时,$x/y=(2q, 2r)$,若$2r\geq y$,则$x/y=(2q+1, 2r-y)$;
当$x=2k+1$且$2r+1<y$时,$x/y=(2q, 2r+1)$,若$2r+1\geq y$,则$x/y=(2q+1, 2r+1-y)$;
写成伪代码就是:
1 | function divide(x, y){ |
具体实现:
1 | pair<Binary, Binary> divide(Binary& x, Binary& y) { |
算法的复杂度与乘法类似,都是$O(n^2)$。
Quick Link: 算法笔记整理