@@ -1190,8 +1190,7 @@ \subsubsection{尾递归}
11901190
11911191作为本节的结尾,我们考虑一个有趣的题目,如何设计一个算法来高效地计算$ b^n$ ?(参考\cite {SICP }中的1.16节。)
11921192
1193- A naive brute-force solution is to repeatedly multiply $ b$ for $ n$ times from 1, which leads to a
1194- linear $ O(n)$ algorithm.
1193+ 最直接的方法是从1开始重复乘以$ b$ 共$ n$ 次,这是一个线性时间$ O(n)$ 的算法。
11951194
11961195\begin {algorithmic }[1]
11971196\Function {Pow}{$ b, n$ }
@@ -1203,21 +1202,18 @@ \subsubsection{尾递归}
12031202\EndFunction
12041203\end {algorithmic }
12051204
1206- Actually, the solution can be greatly improved. Consider we are trying to calculate $ b^8 $ .
1207- By the first 2 iterations in above naive algorithm, we got $ x = b^2 $ . At this stage, we
1208- needn't multiply $ x$ with $ b$ to get $ b^3 $ , we can directly calculate $ x^2 $ , which leads
1209- to $ b^4 $ . And if we do this again, we get $ (b^4 )^2 = b^8 $ . Thus we only need looping 3 times
1210- but not 8 times.
1205+ 我们考虑如何改进它。考虑计算$ b^8 $ 的过程,上述算法经过前两次迭代,可以得到$ x = b^2 $ 的结果。此时,我们无需再次用$ x$ 乘以$ b$ 得到$ b^3 $ ,可以直接再次乘以$ b^2 $ ,从而得到$ b^4 $ 。然后再次乘方,就可以得到$ (b^4 ) = b^8 $ 。这样总共只要循环3次,而不是8次。
12111206
1207+ 若
12121208An algorithm based on this idea to compute $ b^n$ if $ N = 2 ^M$ for some non-negative integer $ m$ can be shown in
12131209the following equation.
12141210
12151211\[
12161212pow(b, n) = \left \{
12171213 \begin {array }
12181214 {r@{\quad :\quad }l}
1219- b & N = 1 \\
1220- pow(b, \frac {N }{2})^2 & otherwise
1215+ b & n = 1 \\
1216+ pow(b, \frac {n }{2})^2 & otherwise
12211217 \end {array }
12221218\right .
12231219\]
@@ -1226,8 +1222,8 @@ \subsubsection{尾递归}
12261222
12271223\begin {itemize }
12281224\item For the trivial case, that $ n$ is zero, the result is 1;
1229- \item If $ n$ is even number, we can halve $ n$ , and compute $ b^{\frac {N }{2}}$ first. Then calculate the square number of this result.
1230- \item Otherwise, $ n$ is odd. Since $ N -1 $ is even, we can first recursively compute $ b^{N -1}$ , the multiply $ b$ one more time to this result.
1225+ \item If $ n$ is even number, we can halve $ n$ , and compute $ b^{\frac {n }{2}}$ first. Then calculate the square number of this result.
1226+ \item Otherwise, $ n$ is odd. Since $ n -1 $ is even, we can first recursively compute $ b^{n -1}$ , the multiply $ b$ one more time to this result.
12311227\end {itemize }
12321228
12331229Below equation formalizes this description.
@@ -1236,9 +1232,9 @@ \subsubsection{尾递归}
12361232pow(b, n) = \left \{
12371233 \begin {array }
12381234 {r@{\quad :\quad }l}
1239- 1 & N = 0 \\
1240- pow(b, \frac {N }{2})^2 & 2 | N \\
1241- b \times pow(b, N -1) & otherwise
1235+ 1 & n = 0 \\
1236+ pow(b, \frac {n }{2})^2 & 2 | n \\
1237+ b \times pow(b, n -1) & otherwise
12421238 \end {array }
12431239\right .
12441240\ee
@@ -1250,30 +1246,30 @@ \subsubsection{尾递归}
12501246pow(b, n) = \left \{
12511247 \begin {array }
12521248 {r@{\quad :\quad }l}
1253- 1 & N = 0 \\
1254- pow(b^2, \frac {N }{2}) & 2 | N \\
1255- b \times pow(b, N -1) & otherwise
1249+ 1 & n = 0 \\
1250+ pow(b^2, \frac {n }{2}) & 2 | n \\
1251+ b \times pow(b, n -1) & otherwise
12561252 \end {array }
12571253\right .
12581254\ee
12591255
1260- With this change, it's easy to get a tail-recursive algorithm as the following, so that $ b^N = pow'(b, N , 1 )$ .
1256+ With this change, it's easy to get a tail-recursive algorithm as the following, so that $ b^n = pow'(b, n , 1 )$ .
12611257
12621258\be
1263- pow'(b, N , A) = \left \{
1259+ pow'(b, n , A) = \left \{
12641260 \begin {array }
12651261 {r@{\quad :\quad }l}
1266- A & N = 0 \\
1267- pow'(b^2, \frac {N }{2}, A) & 2 | N \\
1268- pow'(b, N -1, A \times b) & otherwise
1262+ A & n = 0 \\
1263+ pow'(b^2, \frac {n }{2}, A) & 2 | n \\
1264+ pow'(b, n -1, A \times b) & otherwise
12691265 \end {array }
12701266\right .
12711267\ee
12721268
12731269Compare to the naive brute-force algorithm, we improved the performance to $ O(\lg n)$ .
12741270Actually, this algorithm can be improved even one more step.
12751271
1276- Observe that if we represent $ n$ in binary format $ N = (a_ma_{m-1}...a_1 a_0 )_2 $ , we clear know
1272+ Observe that if we represent $ n$ in binary format $ n = (a_ma_{m-1}...a_1 a_0 )_2 $ , we clear know
12771273that the computation for $ b^{2^i}$ is necessary if $ a_i = 1 $ . This is quite similar to the
12781274idea of Binomial heap (reader can refer to the chapter of binomial heap in this book). Thus
12791275we can calculate the final result by multiplying all of them for bits with value 1.
@@ -1293,12 +1289,12 @@ \subsubsection{尾递归}
12931289Summarize this idea, we can improve the algorithm as below.
12941290
12951291\be
1296- pow'(b, N , A) = \left \{
1292+ pow'(b, n , A) = \left \{
12971293 \begin {array }
12981294 {r@{\quad :\quad }l}
1299- A & N = 0 \\
1300- pow'(b^2, \frac {N }{2}, A) & 2 | N \\
1301- pow'(b^2, \lfloor \frac {N }{2} \rfloor , A \times b) & otherwise
1295+ A & n = 0 \\
1296+ pow'(b^2, \frac {n }{2}, A) & 2 | n \\
1297+ pow'(b^2, \lfloor \frac {n }{2} \rfloor , A \times b) & otherwise
13021298 \end {array }
13031299\right .
13041300\ee
@@ -1307,8 +1303,8 @@ \subsubsection{尾递归}
13071303which is the lowest bit) is 0, it means $ n$ is even. It goes on computing the square of the base, without accumulating the
13081304final product (Just like the 3rd step in above example); If the LSB is 1, it means $ n$ is odd. It squares the base and
13091305accumulates it to the product $ A$ ; The edge case is when $ n$ is zero, which means we exhaust all the bits in $ n$ , thus
1310- the final result is the accumulator $ A$ . At any time, the updated base number $ b'$ , the shifted exponent number $ N '$ ,
1311- and the accumulator $ A$ satisfy the invariant that $ b^N = b'^{N '}A$ .
1306+ the final result is the accumulator $ A$ . At any time, the updated base number $ b'$ , the shifted exponent number $ n '$ ,
1307+ and the accumulator $ A$ satisfy the invariant that $ b^n = b'^{n '}A$ .
13121308
13131309This algorithm can be implemented in Haskell like the following.
13141310
0 commit comments