开平方运算(Non-Restoring)
在书《基于FPGA的数字信号处理》中的开平方运算一节中,作者给出了一种基于Non-Restoring的算法,但是没有给出具体推导过程,本文试图给出算法的简单证明。熟悉十位数的开方运算的读者可以跳转到第二部分
十位数的开平方运算
对于十位数的开方运算,我们有许多算法,比如泰勒展开、牛顿迭代法、利用常数0x5f375a86加速收敛的牛顿迭代法等。在书中使用的是Non-Restoring算法,本文就专门讨论这个算法。
对于一个6位的十位数D,它的每一位用dn表示,即
D
=
d
5
d
4
d
3
d
2
d
1
d
0
D=d_5d_4d_3d_2d_1d_0
D=d5d4d3d2d1d0
它的n次根号的位数为 6 / n位,不严谨的简单证明如下:
一个数字a的整数部分长度为n,小数部分长度为无限长,它的平方的取值范围即为
[
1
0
n
,
1
0
n
+
2
]
[10^n,10^{n+2}]
[10n,10n+2]。
类比除法的运算规则,我们可以利用迭代的减法操作,从高位到低位逐级算出解。
回顾除法运算,例如除法算式
1354
/
3
1354/3
1354/3,我们有如下操作
151
3
)
1354
‾
12
‾
15
15
‾
4
3
‾
1
\begin{array}{lr} & 151 \\ 3 \!\!\!\!\!\! & \overline{)1354} \\ & \underline{12\ \ \ \ } \\ & 15\ \ \\ & \underline{15\ \ } \\ & 4 \\ & \underline{3}\\ & 1 & \end{array}
3151)135412 15 15 431
为了取得每一位的解,在每一位上,我们都需要找出数字n,n满足两个条件:
- n是正整数且只有一位,对于十进制取值范围为{0,1,2,3,4,5,6,7,8,9}。
- {上一次运算的余项,本次运算的被除数对应位} - n * 除数 的值 为最小值。
我们来看看根号的手解法。
D
=
d
5
d
4
d
3
d
2
d
1
d
0
D=d_5d_4d_3d_2d_1d_0
D=d5d4d3d2d1d0
Q
=
D
=
q
2
q
1
q
0
=
q
2
∗
1
0
2
+
q
1
∗
10
+
q
0
Q=\sqrt{D}=q_2q_1q_0=q_2*10^2+q_1*10+q_0
Q=D=q2q1q0=q2∗102+q1∗10+q0
当我们要计算Q时,
q
2
q_2
q2的值可以由
d
5
d
4
d_5d_4
d5d4直接平方后试减得到,如
598213
\sqrt{598213}
598213的百位为7。
可以把算出来的数字设置为a(上句话运算结果为a=700),下一位待计算的值为b。我们可以利用
(
a
+
b
)
2
−
a
2
=
2
a
b
+
b
2
(a+b)^2-a^2=2ab+b^2
(a+b)2−a2=2ab+b2试出数字b,b满足两个条件:
- b是正整数,对于十进制,最高位取值范围为{0,1,2,3,4,5,6,7,8,9},其余位为0。
- 2 a b + b 2 2ab+b^2 2ab+b2 - {上一次运算的余项,本次运算的被除数对应位} 的值 为最小值。
如果a、b的值不包含未计算部分,则上述条件将会有些许变化:
- b是正整数且只有一位,对于十进制,取值范围为{0,1,2,3,4,5,6,7,8,9}
- {上一次运算的余项,本次运算的被除数对应位} 20 a b + b 2 20ab+b^2 20ab+b2 的值 为最小值。
一个例子是
7
7
3
59
82
13
49
‾
10
82
10
29
‾
53
13
46
29
‾
6
84
\begin{array}{lr} & 7\ \ \ 7\ \ \ 3\ \\ \!\!\!\!\!\! & \sqrt{59\ 82\ 13}\\ & \underline{49\ \ \ \ \ \ \ \ \ \ } \\ & 10\ 82\ \ \ \ \ \\ & \underline{10\ 29\ \ \ \ \ } \\ & 53\ 13\\ & \underline{46\ 29}\\ & 6\ 84 & \end{array}
7 7 3 59 82 1349 10 82 10 29 53 1346 296 84
795213
=
77
3
2
+
684
\sqrt{795213} = 773^2+684
795213=7732+684
a | 前次余项+本次运算块 | 20 a b + b 2 20ab+b^2 20ab+b2 | b |
---|---|---|---|
0 | 59 | 49 | 7 |
7 | 1082 | 1029 | 7 |
77 | 5313 | 4629 | 3 |
773 | 684 | - | - |
对于n次根号,我们需要将被n次开方处理的数字每n位分割。将上述迭代减法的计算式换成 ( a + b ) n − a n (a+b)^n-a^n (a+b)n−an即可。
fpga上的开平方运算
针对上述算法我们可以进行电路实现。首先面临的就是进制转换问题。二进制数字的平方与十进制数有很多相似之处,比如:
- 一个定点数二进制数字a的整数部分(无符号位)长度为n,小数部分长度为无限长,它的平方的取值范围即为 [ 2 n , 2 n + 2 ] [2^n,2^{n+2}] [2n,2n+2]
- 它的n次根号的位数为 6 / n位
- 迭代计算中用到的式子同样是 ( a + b ) 2 − a 2 (a+b)^2-a^2 (a+b)2−a2(a、b包括未计算部分),第二种形式为 4 a b + b 2 4ab+b^2 4ab+b2(a、b不包括未计算部分)
不过,二进制数有一些有利的性质,我们可以利用他们来简化大量计算,如迭代用的式子 4 a b + b 2 4ab+b^2 4ab+b2,用二进制表示可以优化为 ( 100 ) b a b + ( b ) 2 = ( a b 0 b ) b (100)_bab+(b)^2=(ab\ 0b)_b (100)bab+(b)2=(ab 0b)b 其中a为一串二进制数,b为一位二进制数。
当迭代的减法式子写作
(
a
b
0
b
)
b
(ab\ 0b)_b
(ab 0b)b时:
1
1
0
1
10
10
10
01
01
‾
01
10
1
01
‾
01
10
00
00
‾
1
10
01
1
10
01
‾
0
\begin{array}{lr} & 1\ \ \ 1\ \ \ 0\ \ \ 1\\ \!\!\!\!\!\! & \sqrt{10\ 10\ 10\ 01}\\ & \underline{01\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ } \\ & 01 \ 10\ \ \ \ \ \ \ \ \ \ \\ & \underline{1\ 01\ \ \ \ \ \ \ \ \ \ } \\ & 01\ 10\ \ \ \ \ \\ & \underline{00\ 00\ \ \ \ \ }\\ & 1\ 10\ 01\\ & \underline{1\ 10\ 01 }\\ &0 & \end{array}
1 1 0 110 10 10 0101 01 10 1 01 01 10 00 00 1 10 011 10 010
(
10101001
)
b
=
(
1101
)
b
2
\sqrt{(10101001)_b} = (1101)_b^2
(10101001)b=(1101)b2
a | 前次余项+本次运算块 | ( a b 0 b ) b (ab\ 0b)_b (ab 0b)b | b |
---|---|---|---|
0 | 010 | 001 | 1 |
1 | 0110 | 101 | 1 |
11 | 0110 | 0000 | 0 |
110 | 11001 | 11001 | 1 |
1101 | 0 | - | - |
此计算过程可以用恢复余数算法表示。
当相减后b<0时,需要恢复相减之前的值。
Restoring 算法很直观,但存在的问题是:若当前部分余数为负时,需要额外的加法操作使其恢复到前一次迭代时产生的部分余数。这不仅需要额外的资源,还增加了Latency。是否可以不恢复余数呢?这需要对算法进行一定的修改。
由式(3.62)可知,式(3.63)可重写为
r
0
=
r
1
D
(
1
)
D
(
0
)
+
q
2
0100
−
q
1
01
r_0=r_1D(1)D(0)+q_20100-q_101
r0=r1D(1)D(0)+q20100−q101
书中的开平方运算
在《基于FPGA的数字信号处理》一书中,用到的算法(Non Restoring)如下:
简单分析可知,书中算法比我们的算法大致相同,不过为了保持运算的一致性,将减法操作统一为加法。图片中有一个错误,即
0
S
3
S
2
11
0S_3S_211
0S3S211应该为
0
S
3
S
2
S
1
11
0S_3S_2S_111
0S3S2S111
看懂这个算法需要两个小知识点:
- A - B = A + ( -B) ,等于A的补码加(-B)的补码
- if (A >= B) A+补(B)将会产生进位
else if(A < B) A+补(B)将不会产生进位
我们可以根据
补
(
余数
:
当前项
)
+
迭代式
补({余数:当前项})+迭代式
补(余数:当前项)+迭代式 是否产生进位来决定下一步迭代的迭代式选取。Q(k+1)代表前一次运算的进位情况,补码情况下
由前文可知,
r
k
=
{
r
k
+
1
D
(
2
k
+
1
)
D
(
2
k
)
−
q
k
+
1
01
if Q(k+1)==1
r
k
+
1
D
(
2
k
+
1
)
D
(
2
k
)
+
q
k
+
1
11
(
if Q(k+1)==0
r_k=\begin{cases} r_{k+1}D(2k+1)D(2k) -q_{k+1}01 &\text{if Q(k+1)==1 }\\ r_{k+1}D(2k+1)D(2k) +q_{k+1}11 ( &\text{if Q(k+1)==0} \end{cases}
rk={rk+1D(2k+1)D(2k)−qk+101rk+1D(2k+1)D(2k)+qk+111(if Q(k+1)==1 if Q(k+1)==0
如果使用补码运算,式子将会修改如下+
r
k
=
{
r
k
+
1
D
(
2
k
+
1
)
D
(
2
k
)
+
0
q
k
+
1
11
if Q(k+1)==0
r
k
+
1
D
(
2
k
+
1
)
D
(
2
k
)
+
1
q
~
k
+
1
11
(
if Q(k+1)==1
r_k=\begin{cases} r_{k+1}D(2k+1)D(2k) +0q_{k+1}11 &\text{if Q(k+1)==0}\\ r_{k+1}D(2k+1)D(2k) +1\widetilde{q}_{k+1}11 ( &\text{if Q(k+1)==1} \end{cases}
rk={rk+1D(2k+1)D(2k)+0qk+111rk+1D(2k+1)D(2k)+1q
k+111(if Q(k+1)==0if Q(k+1)==1
q k q_k qk | r k + 1 D ( 2 k + 1 ) D ( 2 k ) r_{k+1}D(2k+1)D(2k) rk+1D(2k+1)D(2k) | Q ( k + 1 ) ? 0 q k + 1 11 : 0 q k + 1 11 Q(k+1)\ ?\ 0q_{k+1}11\ :\ 0q_{k+1}11 Q(k+1) ? 0qk+111 : 0qk+111 | 进位情况 |
---|---|---|---|
- | 010 | 111 | 1 |
1 | 0110 | 1 S ~ 3 11 = 1011 1\widetilde{S}_311=1011 1S 311=1011 | 1 |
11 | 00110 | 1 S ~ 3 S ~ 2 11 = 10011 1\widetilde{S}_3\widetilde{S}_211=10011 1S 3S 211=10011 | 0 |
110 | 100101 | 0 S 3 S 2 S 1 11 = 011011 0S_3S_2S_111=011011 0S3S2S111=011011 | 1 |
1101 | 0 | - | - |