实现平方根的方法有很多,不同的方法适合于不同的要求、不同的场合。下面介绍常用的几种方法,主要有牛顿迭代法,中值查找法,全硬件电路法和SRT算法。
每种方法从基本原理,实现方法和实例三方面来介绍。1 牛顿迭代法 1.1 基本原理
牛顿迭代法(Newton’s method)又称为牛顿-拉夫逊方法(Newton-Raphson method),它是牛顿在17世纪提出的一种在实数域和复数域上近似求解方程的方法。多数方程不存在求根公式,因此求精确根非常困难,甚至不可能,从而寻找方程的近似根就显得特别重要。方法使用函数F(x)的泰勒级数的前面几项来寻找方程F(x) = 0的根。牛顿迭代法是求方程根的重要方法之一,其最大优点是在方程F(x) = 0的单根附近具有平方收敛,而且该法还可以用来求方程的重根、复根。
设r是 QUOTE 的根,选取x0作为r初始近似值,过点 QUOTE 做出曲线 QUOTE 的切线L,L的方程为
求出L与x轴交点的横坐标:
称x1为r的一次近似值。过点 QUOTE 做出曲线 QUOTE 的切线,并求该切线与x轴的横坐标
称x2为r的二次近似值。重复以上过程,得r的近似值序列,其中
称为r的n+1次近似值,上式称为牛顿迭代公式。
解非线性方程 QUOTE 的牛顿迭代法是把非线性方程线性化的一种近似方法。把F(x)在x0点附近展开成泰勒级数
取其线性部分,作为非线性方程 QUOTE 的近似方程,即泰勒展开的前两项,则有
设 QUOTE 则其解为 QUOTE 这样,得到牛顿法的一个迭代序列:
1.2 实现方法
应用牛顿迭代法求解平方根,即 QUOTE 中已知s的情况下,求满足等式的x的取值,对等式两边进行平方,得 QUOTE ,令 QUOTE 。假设选定x0作为初始近似值,那么下一个近似值x1,如下求得:
曲线 QUOTE 上过点 QUOTE 的切线方程是
其与x轴的交点是 QUOTE 其中
所以递推公式可以表示为:
选定一个初试值x0,经过数次的循环迭代便可以得到满足我们所需精度的最终结果,牛顿迭代法在很多不能用常规方法解答的方程求根问题中应用很广泛。1.3 实例
以求 QUOTE 为例,以x0=30为初值,运用牛顿迭代法求x的近似值。
由递推公式
可以求出递推值:
x0= 30
x1= 19.250
x2= 16.248
x3= 15.971
x4= 15.969
……
x的真实值是保留三位有效数字后是15.969,由递推得到的递推值随着次数的增加,慢慢逼近真实值,根据你所要的精度来确定具体所需要递归的次数。2 中值查找法 2.1 基本原理
中值法是由对半查找(Binary Search)演变过来的,它原先是一种高效的查找方法,假定有一串数字a1,a2,a3,a4,a5,……,an,已经按从小到大的顺序排列好,那么,要查找一个已知是属于该字串的数ar在这串数字中的位置。
基本思想是,首先ar与表中间(记录)的关键词 an/2比较,其结果有三种情况:(ar<an/2; ar= an/2; ar>an/2);然后根据比较结果就能确定下一次应该到表的哪一半中去查找(或查找成功),并对确定了的这一半重复上述过程,如此下去直到表的长度递减为1,最终查找找到确定的目标。如图所示过程:
图 半值查找法单次流程
以上示范的是一个查找过程,当完成后,确定新的查找范围继续这个过程进行查找,经过数次的查找以后,不断地缩小范围,最后必然剩余一个或者两个数(由查找范围的奇偶个数决定)进行比较,最终可以确定出所查找的位置。
查找的次数由原数串的长度决定,采用了半值查找法,最多所需要查找的次数是 QUOTE ,其中s是数串的总个数。2.2 实现方法
整数平方根所需要求的结果是整数,32位的整数开方,得到的结果必然是16位的,所以在1到16位的二进制数中查找如下满足条件的值,被查数的平方和给出的平方值相等,查到这样的数就是最终开方得到的结果。
从0到216作为查找的对象,初始下界是0,上界是216,判断查找对象的中间值 QUOTE 的平方与给的被开方数s的关系,若s较大,则继续查找,而且查找的范围变为215~216;若s较小,则还是继续查找,而且查找的范围变为0~215;若与s相等,则停止查找,确定最终要求的值。若要继续查找,则根据新的查找范围继续查找,直到找到最接近的值停止查找,输出最终结果。2.3 实例
以求 QUOTE 为例,确定上界是216,下界是0,查找过程如下:
表中值法查找 QUOTE 整数部分的过程
序号
查找范围
中值
中值平方
与255关系
结论
1
0~216
215
230
>
新查找范围0~215
2
0~215
214
228
>
新查找范围0~214
3
0~214
213
226
>
新查找范围0~213
4
0~213
212
224
>
新查找范围0~212
5
0~212
211
222
>
新查找范围0~211
6
0~211
210
220
>
新查找范围0~210
7
0~10
29
218
>
新查找范围0~29
8
0~29
28
216
>
新查找范围0~28
9
0~28
27
214
>
新查找范围0~27
10
0~27
26
212
>
新查找范围0~26
11
0~26
25
210
>
新查找范围0~25
12
0~25
24
28
>
新查找范围0~24
13
0~24
23
26
<
新查找范围23~24
14
23~24
12
144
<
新查找范围12~24
15
12~24
14
196
<
新查找范围14~24
16
14~24
15
225
<
查找到相邻数,结束
查找结束的判断,一种情况是当中间值的正好等于被开方数时,停止查找,确切的根已经找到,而且余数是0,另外一种情况就是当查找到下限,中间值,上限是三个相邻的整数,那么查找也结束,确定中间值是所需要查找的目标,余数利用减法运算得出。
当查找到相邻数,即没有中间的整数值可以被用来比较了,说明最后被找到中间值15是最接近 QUOTE 的整数,然后求出余数为 QUOTE 。3 模拟硬件电路法 3.1 基本原理
两个相同的数通过乘法器便得到这个数的平方,只要利用运算放大器将其输出作为乘法器的输入端,反馈到运算放大器的输入端,适当得控制运算放大器正负端入端所接电阻的阻值就可以实现平方根关系的输出了。3.2 实现方法
利用模拟乘法器与运放构成的负电压平方根运算电路如图所示
图 硬件实现开方电路
模拟乘法器和运放的组合负电压平方根电路,它的计算过程如下:
根据虚短虚断的规律得到运放的输入输出端口的电位为0,与地相同,所以有:
即:
由乘法器的运算规律可以知道,乘法器输出端的电压与输入端的电压平方关系:
由以上得出的两个关系可以推出如下的关系来,即是我们所期望的平方根关系。
3.3 实例
选择合适的参数,具体参数如图,可以利用公式得出输入电压的开方的值。
图 硬件实现9的开方电路
可以计算出V0=3(V)4 SRT算法 4.1 数字迭代平方根的原理
开方的操作定义如下:
数字平方根是利用数字求商的原理,每个迭代过程都是一次求商的过程,产生商和余数,也就是算平方根的。
数字迭代由若干次迭代实现,每次迭代产生一个商数字,其中高有效位在前。j次迭代后的商记作s[j],即:
qi表示第i次的商数,r是基数。
从而,最终的商是
定义部分余数w是
d[j]是本次求商运算中的除数。
qi的值通过商选择函数来确定。
将所有商的位数确定以后,最终的商也就出来了,这个结果就是我们所需要的整数平方根的值,最后的余数就是我们需要的平方根的余数。4.2 平方根方法与实现过程
由于迭代过程的除法是在二进制数中进行的,其每位商数的结果只有两种,0或者1,这对于商的选择十分的便利。因为对于二进制来说,0和1的性质以及二进制以2为底的性质都可以利用上来:
(1)一个数的平方等于本身,0的平方是0,1的平方是1;
(2)0乘以任何数结果为0;
(3)乘以2i就是左移i位,除以2i就是右移i位。
具体应用如下:
当x2=0时, QUOTE
当x2=1时, QUOTE
假设 QUOTE ,那么当高位x1确定以后,余数
这个式子满足x2=0和x1=1的两种情况。
由上式可求出x2的具体数值。4.2.1 迭代过程中输入量的确定
将被开方数按每两位作为一组,32位的二进制数可以分的组数是16组(包括无意义的0)。
迭代过程是一个求商的过程,求商用的输入量无非就是除数与被除数。只要确定了除数与被除数进而就可以确定商与余数了。
每组数运算时被除数的确定方法:将上一个迭代过程的余数左移两位,再加上被开方数中的下一组数。
每组数运算时除数的确定方法:已经确定的商数左移两位,加上本次所要上的商。4.2.2 迭代过程中输出量的确定
迭代过程是一个求商的过程,输出量就是商数与余数。每一次的商数由商选择函数确定,选0还是选1由调用选择函数来确定,本次迭代的余数即部分余数在确定本次迭代的商数以后,由被除数减去除数乘以商数来计算得到。
每个迭代过程的输出量是部分输出量,然后商数从高位到低位组成平方根,最后一次迭代的部分余数作为最终的余数。4.2.3 选择函数
选择函数就是确定最终是商0还是1的函数,问题等价于已知除数和被除数的两个值的情况下怎样求出商数的问题。
这个过程的方法是:先试商1,如果不满足,那么就是商0。
在试商1的假设情况下,根据除数与被除数的产生方法:被除数由上一次迭代的部分余数左移两位,加上后一组被开方数;除数由已经确定的商数左移2位,加上1。
比较除数与被除数的大小:如果被除数大,那么说明试商1是可行的,部分商为1,部分余数是由被除数减去除数得到的结果;如果除数大,那么说明试商1是不可行的,部分商为0,部分余数就是被除数。4.2.4 计算过程图
SHAPE \* MERGEFORMAT置初始值
循环迭代16次
输出结果
产生被除数
产生除数
商选择
试商1
确定商的结果
计算余数的值
图计算的过程图
过程图说明:
将整个过程分为三个层次进行,在每个层次中比较复杂的过程又是由下一层次的运算过程决定的。
首先,将任务分为三个部分,分别是初始化过程,迭代过程,输出过程,其中迭代过程需执行16次,这样才能获得最终结果;
其次,每个循环过程又可以分为三个步骤,除数的产生,被除数的产生,商的选择,前两步是对初试数据的变换运算。
最后,商选择是对0和1进行试探的过程,先试商1,如果试商成功,那么1就是商,如果试商不成功,那么0就是商,最后根据确定的商来计算余数。4.2.4 程序算法流程图
SHAPE \* MERGEFORMAT次数少于16次
次数满足16次次
开始
获取被开方数
被开方数赋给余数(被除数)变量
{被开方数,余数} 组成新变量整体左移2位
商数左移2位+1
计算比较变量=被除数(余数)-除数
商数左移1位+1
余数等于比较变量
商数左移1位
判断计算次数
输出商数与余数
结束
次数增加1
图 程序算法流程图
流程图说明:
程序一开始是获取输入的被开方数,被除数是由余数变换过来的,所以,被除数和余数可以使用一个变量,余数的初始值就是被开方数本身。
将被开方数,余数都左移2位,其中余数移入的末两位是被开方数移出的前两位,商选择的被除数和除数就产生了,后面开始就是商选择了。
商数左移2位再加1是作为试商1的准备,然后判断比较变量的符号,若为负数则商0,商数左移1位,余数就是被除数;若为非负数则商1,商数左移1位再加1,余数是比较变量的值。
总共需要循环16次,所以必须判断次数,若次数已经到了就输出商数与余数,若次数未到就继续迭代运算。4.3 手算实例
下面举两个例子,更好地说明本算法的计算过程:
(1)计算二进制数中1的个数是奇数的数值127的平方根,要求求出其整数部分和它的余数,首先将127化为二进制的数(127)10=(0000000000000000000000001111111)2,然后将其每两个二进制位分为一组,形式如下进行计算。
图4-3 (127)10的二进制平方根手算过程
按除法的手算做法,开始都是0,肯定是商0,图中省略的是商0的情况。当出现1的时候,确定要商1,然后按照除数的构造方法,其中(1)2,(100)2,(1001)2,(10101)2都是构造的除数,(0)2,(01)2,(011)2,(1111)2,(11011)2,(110)2是每次商运算后的部分余数,其中(110)2是最终余数。
由图4-3可知,其手算的商就是平方根的整数部分,余数就是我们需要的余数,所以,满足 QUOTE ,即十进制表示为式子是 QUOTE ,结果是正确的。
(2)计算二进制数中1的个数是偶数的数值841的平方根,要求求出其整数部分和它的余数,首先将127化为二进制的数(841)10=(0000000000000000000001101111011)2,然后将其每两个二进制位分为一组,形式如下进行计算。
图4-4 (841)10的二进制平方根手算过程
按除法的手算做法,开始都是0,肯定是商0,当出现1的时候,确定要商1,然后按照除数的构造方法,其中(1)2,(101)2,(1101)2,(11101)2,(111001)2都是构造的除数,(0)2,(10)2,(100)2,(110)2,(11010)2,(110010)2是每次作商运算后的部分余数,其中(110010)2是最终余数。
由图4-3可知,其手算的商就是平方根的整数部分,余数就是我们需要的余数,所以,满足 QUOTE ,即十进制表示为式子是 QUOTE ,结果是正确的。4.4关键代码概述
本算法使用verilog硬件描述语言编写的,由算法文件sqrt.v和测试文件test.v组成。
(1)sqrt.v的输入输出
module sqrtnum(numin,reset,clk,sqrt,rem,eop);
定义输出输入量,其中numin,reset,clk是输入量,sqrt,rem,eop是输出量,numin是需要计算平方根值的数;reset是重置信号,下降沿时重置初始值,clk是时钟信号,在clk的上升沿进行求平方根运算;eop是结束信号(End Of Process)当计算结果满足要求以后,eop信号输出上升沿。
(2)sqrt.v的重置过程
always @(negedge reset)
begin
sqrtreginitial=0;
remreginitial=0;
divinitial=0;
tmpinitial=0;
numinitial=numin;
iinitial=0;
jinitial=0;
end
以上代码表示在reset信号的下降沿时,将一些输入输出和中间变量初始化。
(3)迭代前的准备
if(num==0)
begin
sqrtreg=0;
remreg=0;
disable calsqrt;
end
当输入的变量是0时,直接退出整个迭代过程,如果是0,直接输出结果,平方根和余数都为0,eop信号产生上升沿。
循环迭代的次数count变量是固定的16次,可以对循环迭代次数进行如下的改进:
for(i=0;i<31;i=i+1)
begin
count=(31-i)>>1;
h=(count<<1)+1;
count=count+1;
if(numin[31-i]||0)disable calh;
end
利用循环测试的方法,将31位二进制数中高位无意义的0全部忽略掉,找出第一个最高位不为0所在的位数,这是由于高位无意义的0带来的商数是0,在平方根中也是无意义的。
(4)sqrt.v的迭代过程
begin always @(posedge clk)
begin:calsqrt
$display(“Calculating Squart…”);
for(j=0;j<16;j=j+1)
begin
//prepare for Quotient Chosen
remreg=(remreg<<2)+(num[h]<<1)+(num[h-1]); (*)
num=num<<2;
div=(sqrtreg<<2)+1;
tmp=remreg-div;
//Choose Quotient (**)
if(tmp>=0)
sqrtreg=(sqrtreg<<1)+1;
remreg=remreg-div;
end
else
begin
sqrtreg=sqrtreg<<1;
end
//When The Variable Count Reaches 0, Display And Finish (***)
if(count==j+1)
begin
$display(“TestNum:%d;SQRT:%d;REM:%d”,numin,sqrtreg,remreg);
disable calsqrt;
end
$display(“End Calculating Squart…”);
End
(*) 行处是产生商选择的除数与被除数部分。
(**) 行处开始是商选择部分,根据对tmp变量,即除数与被除数差的正负判断确定商是0还是1。
(***) 行开始表示循环的结束判断过程,当j这个循环变量到达count计数值时,显示结果,跳出循环。
(5)test.v的初始化
initial
begin
testnum=0;
sel=1;
rst=1;
#2 rst=0;
k=0;
end
对要被调用的变量进行初始化,其中rst是重置信号,需要一个下降沿。
(6)test.v的输入控制信号
//clock signal
always #2 sel=~sel;
always @(negedge rst) #1 rst=1;
always @(posedge eop)
begin
testnum=testnum+20;
#2
rst=0;
end
sel是选中即时钟信号;rst重置信号的低电平脉冲时间是一个时间单位;eop结束信号的作用是捕获到一个计算过程结束后,延迟2个时间单位将测试数据加20作为新的测试数据,然后重置计算过程。
(7)调用算法过程
sqrtnum s( .numin(testnum), .reset(rst), .clk(sel), .sqrt(sr), .rem(rm), .eop(eop));
4.5 算法特点
(1)适合于整数的运算,本方法得到的两个结果都是整数,其整数都是在32位的整数值范围内。
(2)高位到低位的运算顺序
(3)除法思想方法的运用,从手算实例可以看出,本文对平方根算法的实现是采用类似于除法的方法,对于二进制商是0还是1比较好判断,只要采用试商的方法,还是比较直观的。