查找表开方的方法主要分为两个步骤:
1、查找表的制定;
2、 Leading位的计算 ,查表并输出开方数。
1.1 查找表的制定
查找表的制定主要是两 个参数:
查找表的地址 宽度 :由 leading长度决定
查找表的数据宽度 :由误差决定 。
这两个参数主要是通过计算该两个参数对查表误差的影响来进行确定。 这里以查找表地址宽度为 8位、查找表的数据宽度 为 11位,即 addr_bit=leading_bit=8,rom_bit=11为例进行讲解
1.2 被开方数的值
由于地址宽度为8位, 此时可以表示的被开方数 为 0~255。 但是由于 本设计采用的是两位 leading位判断方式,因此 leading_bit的高两位只能为 2’b01 2’b10以及 2’b11(后续介
绍 leading会介绍) 。 因此无法寻址到 0~63地址,即查找表有四分之一的地址是浪费的。 此时被开方数可以表示的数为 2
𝑙𝑒𝑎𝑑𝑖𝑛𝑔_𝑏𝑖𝑡−2
~2
𝑙𝑒𝑎𝑑𝑖𝑛𝑔_𝑏𝑖𝑡
−1,即 64~255。 此时 其对应的开方值
为 floor[sqrt(2
𝑙𝑒𝑎𝑑𝑖𝑛𝑔_𝑏𝑖𝑡−2
)~sqrt(2
𝑙𝑒𝑎𝑑𝑖𝑛𝑔_𝑏𝑖𝑡
− 1)]即 floor[sqrt(64)~sqrt(255)]。 由于此时用的开方数是截位之后的数,比截位前的数肯定要小,估算的值肯定也偏小。 如果保留截位的值,即在截位处处添加小数点,后面的值的范围为添加小数点,后面的值的范围为0~0.999999,因此,因此在确认好是查找表的第几个数之后,在确认好是查找表的第几个数之后,被被开方数加上开方数加上0.5来平衡误差。来平衡误差。即开方即开方后的后的数为数为floor[sqrt(𝑎𝑑𝑑𝑟+0.5)]。
1.3 查找表中的值
由于开方数的长度为leading_bit的长度,即为8位,在开方之后的数的长度 为 leading_bit长度的一半,即为 4。 此时由于设置的数据宽度为 rom_bit,即 11位。 因此需要将 4位扩展
到 11位,即将 leading_bit长度的一半扩展到 rom_bit,需要乘 2
𝑟𝑜𝑚_𝑏𝑖𝑡−(𝑙𝑒𝑎𝑑𝑖𝑛𝑑_𝑏𝑖𝑡/2)
,即乘2
7
。 由于被开方数最小为 64.5,因此最小开方后的数大于 8,且开方后的数为 4位,也就是
说所有开方 后的数的最高位都为 1 因此可以省略最高位来减小后续硬件实现的资源。 对于查找表而言,存在查找表中的开方后的数省略最高位就是减去 2
𝑟𝑜𝑚_𝑏𝑖𝑡−1
,即减去 1024。此
时的值才为最终存储在查找表中的值 ,其为rom(addr)=floor[ sqrt(𝑎𝑑𝑑𝑟+0.5) × 2
𝑟𝑜𝑚_𝑏𝑖𝑡
−(𝑙𝑒𝑎𝑑𝑖𝑛𝑔_𝑏𝑖𝑡 / 2) ]-2
𝑟𝑜𝑚_𝑏𝑖𝑡−1
1.4 开方的估算
在得到了查找表之后,根据查找表即可实现
开方 运算, 具体步骤如下:
1、计算 leading位
常见的查找leading位一般是找最高非零位,在找到 leading位为第 M位 (从 0开始计数) 之后,从该位开始向低位方向连续取 L位数据(如果取到 LSB不足 L位,则以 零补足
相当于右移了 M-L+1位,所以需要恢复原被开方数值的话再左移 M-L+1位 。 设被开方的数据为 𝑥
𝐿
,则有开方后的数为 𝑦= 𝑥
0.5
≈ (𝑥
𝐿
× 2
𝑀−𝐿+1
)
0.5
则将被开方数转为了L位数据开方运算,且 L位数据开方的运算可以通过查找表得到。
这里存在一个情况,当剩余位数位奇数时,需要乘 √2再进行截尾,会有额外的乘法操作。因此 对 leading位的判断进行优化,即用两位一组去判断 leading位, 每次移动两位来检
测两位中是否含有 1,如果有,高位即位 leading位 即用 M=𝑓𝑙𝑜𝑜𝑟(𝑙𝑜𝑔2(𝑋)/2+1)∗2来计算 leading位 (从 1开始计数的向偶数取整 )。因为leading位为 M位 (从 1开始计数 ),所以该数据总共有 M位,减去 L位 ,还剩 M-L位
2、截位
在确定leading位 为第 M位 之后 (从 1开始计) ),根据 leading_bit进行截位 。 即将 M-leading_bit后的几位截掉,相当于除以 2
𝑀−𝑙𝑒𝑎𝑑𝑖𝑛𝑔_𝑏𝑖𝑡
。 此时得到的 floor[ 𝑥 / (2
𝑀−𝑙𝑒𝑎𝑑𝑖𝑛𝑔_𝑏𝑖𝑡
) ]的
值就是 查找表的地址的值 matlab中需要加 1 。
3、查表
根据上述获得的查找表地址 floor[ 𝑥 / (2
𝑀−𝑙𝑒𝑎𝑑𝑖𝑛𝑔_𝑏𝑖𝑡
) ]进行查找表查询, 得到的值为省略了最高位 1的值,因此需要对该值的最高位补 1 相当于加 2
𝑟𝑜𝑚_𝑏𝑖𝑡−1
。 此时得到的值为:
sqrt_tmp = rom( floor[ 𝑥 / (2
𝑀−𝑙𝑒𝑎𝑑𝑖𝑛𝑔_𝑏𝑖𝑡
) ]) + 2
𝑟𝑜𝑚_𝑏𝑖𝑡−1
4、 计算
由于在制作查找表的时候对开方后的数进行了扩展到rom_bit位宽以及在查找时进行了截位两部分操作,因此需要对这两部分操作进行恢复。
扩展恢复:除以 2
𝑟𝑜𝑚_𝑏𝑖𝑡−(𝑙𝑒𝑎𝑑𝑖𝑛𝑑_𝑏𝑖𝑡/2)
截位恢复:
乘以 2
(𝑀−𝑙𝑒𝑎𝑑𝑖𝑛𝑔_𝑏𝑖𝑡)/2
,这里乘的是前述被开方数的一半,这是因为在开方之后,开方后的 数 的位宽为被开方数的一 半 。因此最终得到的开方数为:
sqrt= sqrt_tmp ×2
(𝑀−𝑙𝑒𝑎𝑑𝑖𝑛𝑔_𝑏𝑖𝑡)/2
÷ 2
𝑟𝑜𝑚_𝑏𝑖𝑡−(𝑙𝑒𝑎𝑑𝑖𝑛𝑑_𝑏𝑖𝑡/2),
即sqrt= sqrt_tmp ×2
𝑀/2−𝑟𝑜𝑚_𝑏𝑖𝑡
从最终的公式也可以看出, 其中 M一定为偶数,且 rom_bit为整数,因此不会再有 乘 √2的额外操作 。
% module name: sqrt_rom
% Description: The lookup table square root function.
% leading位计算平方根
% 输入:Q48
% 输出:Q24
% sqrt_out = X^0.5
% 256X10
function sqrt_out = sqrt_rom(X)
leading_bit = 8;%查找表leading位
addr_bit = leading_bit;
rom_bit = 11;%实际rom_bit少1位,因为最高位恒为1不用存
rom = zeros(2^addr_bit,1);
for addr = 2^(addr_bit-2):2^addr_bit-1
%计算值的时候,需要补充恒为1的最高位;
%0.5用于使输出结果上下浮动,而不是始终偏大
rom(addr+1) = floor( 2^(rom_bit - leading_bit/2) * (sqrt(addr + 0.5 )) );
rom(addr+1) = rom(addr+1) - 2^(rom_bit-1);%最高位恒为1,不需要储存
%计算非零位数
if X==0
M= 0;
M= floor(log2(X)/2+1)*2;
%计算leading位并查表
%若leading位不足addr_div位,在末尾补0,补足10位
%if M > addr_div
leading = floor( X/2^(M-leading_bit) );%截取leading后多余位数,范围256~1023
if leading== 0
sqrt_tmp1 = 0;
sqrt_tmp1 = rom(leading + 1) + 2^(rom_bit-1);%查找表,并补充最高位1 %20210729
sqrt_tmp2 = floor(sqrt_tmp1* 2^((M-leading_bit)/2) / 2^(rom_bit - leading_bit/2)) ; %除以查找表扩大的倍数
sqrt_out = sqrt_tmp2;