基于FPGA的数字信号处理3.7开平方运算分析

本文详细介绍了非恢复性(Non-Restoring)开平方运算的原理,从十进制的算法出发,通过类比除法运算规则,阐述了如何逐位计算平方根。接着,将算法应用于FPGA(Field-Programmable Gate Array)数字信号处理中,探讨了二进制下的迭代计算和进制转换,并分析了如何通过调整算法减少资源消耗和延迟。最后,对比了恢复余数算法,指出非恢复性算法的优势在于避免了额外的加法操作。

开平方运算(Non-Restoring)

在书《基于FPGA的数字信号处理》中的开平方运算一节中,作者给出了一种基于Non-Restoring的算法,但是没有给出具体推导过程,本文试图给出算法的简单证明。熟悉十位数的开方运算的读者可以跳转到第二部分

十位数的开平方运算

对于十位数的开方运算,我们有许多算法,比如泰勒展开、牛顿迭代法、利用常数0x5f375a86加速收敛的牛顿迭代法等。在书中使用的是Non-Restoring算法,本文就专门讨论这个算法。
对于一个6位的十位数D,它的每一位用dn表示,即
D=d5d4d3d2d1d0D=d_5d_4d_3d_2d_1d_0D=d5d4d3d2d1d0
它的n次根号的位数为 6 / n位,不严谨的简单证明如下:
一个数字a的整数部分长度为n,小数部分长度为无限长,它的平方的取值范围即为[10n,10n+2][10^n,10^{n+2}][10n,10n+2]

类比除法的运算规则,我们可以利用迭代的减法操作,从高位到低位逐级算出解。
回顾除法运算,例如除法算式 1354/31354/31354/3,我们有如下操作
1513 ⁣ ⁣ ⁣ ⁣ ⁣ ⁣)1354‾12    ‾15  15  ‾43‾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满足两个条件:

  1. n是正整数且只有一位,对于十进制取值范围为{0,1,2,3,4,5,6,7,8,9}。
  2. {上一次运算的余项,本次运算的被除数对应位} - n * 除数 的值 为最小值。

我们来看看根号的手解法。
D=d5d4d3d2d1d0D=d_5d_4d_3d_2d_1d_0D=d5d4d3d2d1d0
Q=D=q2q1q0=q2∗102+q1∗10+q0Q=\sqrt{D}=q_2q_1q_0=q_2*10^2+q_1*10+q_0Q=D=q2q1q0=q2102+q110+q0
当我们要计算Q时,q2q_2q2的值可以由d5d4d_5d_4d5d4直接平方后试减得到,如598213\sqrt{598213}598213的百位为7。
可以把算出来的数字设置为a(上句话运算结果为a=700),下一位待计算的值为b。我们可以利用(a+b)2−a2=2ab+b2(a+b)^2-a^2=2ab+b^2(a+b)2a2=2ab+b2试出数字b,b满足两个条件:

  1. b是正整数,对于十进制,最高位取值范围为{0,1,2,3,4,5,6,7,8,9},其余位为0。
  2. 2ab+b22ab+b^22ab+b2 - {上一次运算的余项,本次运算的被除数对应位} 的值 为最小值。

如果a、b的值不包含未计算部分,则上述条件将会有些许变化:

  1. b是正整数且只有一位,对于十进制,取值范围为{0,1,2,3,4,5,6,7,8,9}
  2. {上一次运算的余项,本次运算的被除数对应位} 20ab+b220ab+b^220ab+b2 的值 为最小值。

一个例子是
7   7   3  ⁣ ⁣ ⁣ ⁣ ⁣ ⁣59 82 1349          ‾10 82     10 29     ‾53 1346 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=7732+684\sqrt{795213} = 773^2+684795213=7732+684

a前次余项+本次运算块20ab+b220ab+b^220ab+b2b
059497
7108210297
77531346293
773684--

对于n次根号,我们需要将被n次开方处理的数字每n位分割。将上述迭代减法的计算式换成(a+b)n−an(a+b)^n-a^n(a+b)nan即可。

fpga上的开平方运算

针对上述算法我们可以进行电路实现。首先面临的就是进制转换问题。二进制数字的平方与十进制数有很多相似之处,比如:

  1. 一个定点数二进制数字a的整数部分(无符号位)长度为n,小数部分长度为无限长,它的平方的取值范围即为[2n,2n+2][2^n,2^{n+2}][2n,2n+2]
  2. 它的n次根号的位数为 6 / n位
  3. 迭代计算中用到的式子同样是(a+b)2−a2(a+b)^2-a^2(a+b)2a2(a、b包括未计算部分),第二种形式为4ab+b24ab+b^24ab+b2(a、b不包括未计算部分)

不过,二进制数有一些有利的性质,我们可以利用他们来简化大量计算,如迭代用的式子4ab+b24ab+b^24ab+b2,用二进制表示可以优化为(100)bab+(b)2=(ab 0b)b(100)_bab+(b)^2=(ab\ 0b)_b(100)bab+(b)2=(ab 0b)b 其中a为一串二进制数,b为一位二进制数。

当迭代的减法式子写作(ab 0b)b(ab\ 0b)_b(ab 0b)b时:
1   1   0   1 ⁣ ⁣ ⁣ ⁣ ⁣ ⁣10 10 10 0101               ‾01 10          1 01          ‾01 10     00 00     ‾1 10 011 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)b2\sqrt{(10101001)_b} = (1101)_b^2(10101001)b=(1101)b2

a前次余项+本次运算块(ab 0b)b(ab\ 0b)_b(ab 0b)bb
00100011
101101011
11011000000
11011001110011
11010--

此计算过程可以用恢复余数算法表示。
在这里插入图片描述
当相减后b<0时,需要恢复相减之前的值。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Restoring 算法很直观,但存在的问题是:若当前部分余数为负时,需要额外的加法操作使其恢复到前一次迭代时产生的部分余数。这不仅需要额外的资源,还增加了Latency。是否可以不恢复余数呢?这需要对算法进行一定的修改。
由式(3.62)可知,式(3.63)可重写为r0=r1D(1)D(0)+q20100−q101r_0=r_1D(1)D(0)+q_20100-q_101r0=r1D(1)D(0)+q20100q101
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

书中的开平方运算

在《基于FPGA的数字信号处理》一书中,用到的算法(Non Restoring)如下:
在这里插入图片描述

简单分析可知,书中算法比我们的算法大致相同,不过为了保持运算的一致性,将减法操作统一为加法。图片中有一个错误,即0S3S2110S_3S_2110S3S211应该为0S3S2S1110S_3S_2S_1110S3S2S111
看懂这个算法需要两个小知识点:

  1. A - B = A + ( -B) ,等于A的补码加(-B)的补码
  2. if (A >= B) A+补(B)将会产生进位
    else if(A < B) A+补(B)将不会产生进位

我们可以根据 补(余数:当前项)+迭代式补({余数:当前项})+迭代式(余数:当前项)+迭代式 是否产生进位来决定下一步迭代的迭代式选取。Q(k+1)代表前一次运算的进位情况,补码情况下
由前文可知,
rk={rk+1D(2k+1)D(2k)−qk+101if Q(k+1)==1 rk+1D(2k+1)D(2k)+qk+111(if Q(k+1)==0r_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
如果使用补码运算,式子将会修改如下+
rk={rk+1D(2k+1)D(2k)+0qk+111if Q(k+1)==0rk+1D(2k+1)D(2k)+1q~k+111(if Q(k+1)==1r_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)+1qk+111(if Q(k+1)==0if Q(k+1)==1

qkq_kqkrk+1D(2k+1)D(2k)r_{k+1}D(2k+1)D(2k)rk+1D(2k+1)D(2k)Q(k+1) ? 0qk+111 : 0qk+111Q(k+1)\ ?\ 0q_{k+1}11\ :\ 0q_{k+1}11Q(k+1) ? 0qk+111 : 0qk+111进位情况
-0101111
101101S~311=10111\widetilde{S}_311=10111S311=10111
11001101S~3S~211=100111\widetilde{S}_3\widetilde{S}_211=100111S3S211=100110
1101001010S3S2S111=0110110S_3S_2S_111=0110110S3S2S111=0110111
11010--
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值