verilog中对浮点数的处理

算法中常常会到浮点数运算,而浮点数的处理常常是Verilog初学中常常遇到的问题。以下将就一个简单的例子说明Verilog中浮点数运算处理。

在JPEG图像压缩时遇到色彩空间变换的问题,将YCbCr转换到RGB会遇到浮点数的运算,这个实现复杂,以摄氏温度转换为华氏温度为例  : F = C x 1.8  + 32

R = 1.164(Y-16) + 1.596(Cr-128) 

G = 1.164(Y-16) - 0.391(Cb-128) - 0.813(Cr-128) 

B = 1.164(Y-16) + 2.018(Cb-128) 

module C2F( iclk,irstn,ic,of);
  input  iclk;
  input  irstn;
  input[7:0]  ic;
  output[10:0]  of;
 
 reg[7:0] c;
 reg[10:0] of;
   always@(posedge iclk or negedge irstn)
    begin 
         if(!irstn) 
               begin 
                c <= 0;
                of  <= 0;
         end 
        else
      begin 
               c   <= ic;   
              of  <= c * 1.8 + 32;        // 直接处理,在ISE中综合时会报出错 
             end                            //ERROR:Xst:850 - "C2F.v" line 31: Unsupported real constant. 
      end
endmodule 

上面直接用浮点数进行乘法运算显然是会出错的!!

//以下为改正后的程序
module C2F( iclk,irstn,ic,of);
   input  iclk;
   input  irstn;
   input[7:0]  ic;
   output[10:0]  of;
 
  reg[7:0] c;
  reg[10:0] of;
  reg[10:0] sum;
    always@(posedge iclk or negedge irstn)
           begin 
    if(!irstn) 
                          begin 
      //c <= 0;
        of  <= 0;
        sum  <= 0;
                          end 
                  else 
                          begin 
          // c    <= ic;   
  sum  <= ic * 7+ 128;
   of   <= (sum >>2);      //实际是 近似计算:of=(ic*7+128)/4=ic*1.75+32,
                           end 
            end
endmodule 

将浮点数乘以相同的扩展倍数,然后再将所得结果除以扩展位,这样可以达到近似精确的效果!!

定点小数,就是小数点的位置是固定的。我们是要用整数来表示定点小数,由于小数点的位置是固定的,所以就没有必要储存它(如果储存了小数点的位置,那就是浮点数了)。既然没有储存小数点的位置,那么计算机当然就不知道小数点的位置,所以这个小数点的位置是我们写程序的人自己需要牢记的!

先以10进制为例:如果我们能够计算12+34=46的话,当然也就能够计算1.2+3.4 或者 0.12+0.34了。所以定点小数的加减法和整数的相同,并且和小数点的位置无关。乘法就不同了。 12*34=408,而1.2*3.4=4.08。这里1.2的小数点在第1位之前,而4.08的小数点在第2位之前,小数点发生了移动。所以在做乘法的时候,需要对小数点的位置进行调整?!可是既然我们是做定点小数运算,那就说小数点的位置不能动!!怎么解决这个矛盾呢,那就是舍弃最低位。 也就说1.2*3.4=4.1,这样我们就得到正确的定点运算的结果了。所以在做定点小数运算的时候不仅需要牢记小数点的位置,还需要记住表达定点小数的有效位数。上面这个例子中,有效位数为2,小数点之后有一位。

现在进入二进制:我们的定点小数用16位二进制表达,最高位是符号位,那么有效位就是15位。小数点之后可以有0 - 15位。我们把小数点之后有n位叫做Qn,例如小数点之后有12位叫做Q12格式的定点小数,而Q0就是我们所说的整数。

Q12的正数的最大值是 0 111 . 111111111111,第一个0是符号位,后面的数都是1,那么这个数是十进制的多少呢,很好运算,就是 0x7fff / 2^12 = 7.999755859375。对于Qn格式的定点小数的表达的数值就它的整数值除以2^n。在计算机中还是以整数来运算,我们把它想象成实际所表达的值的时候,进行这个运算

反过来把一个实际所要表达的值x转换Qn型的定点小数的时候,就是x*2^n了。例如 0.2的Q12型定点小数为:0.2*2^12 = 819.2,由于这个数要用整数储存, 所以是819 即 0x0333。因为舍弃了小数部分,所以0x0333不是精确的0.2,实际上它是819/2^12 =0.199951171875

我们用数学表达式做一下总结:
x表示实际的数(一个浮点数), q表示它的Qn型定点小数(一个整数)。
q = (int) (x * 2^n)
x = (float)q/2^n

由于/ 2^n和* 2^n可以简单的用移位来计算,所以定点小数的运算比浮点小数要快得多。下面我们用一个例子来验证一下上面的公式:
用Q12来计算2.1 * 2.2,先把2.1 2.2转换为Q12定点小数:
2.1 * 2^12 = 8601.6 = 8602
2.2 * 2^12 = 9011.2 = 9011
(8602 * 9011) >> 12 = 18923

18923的实际值是18923/2^12 = 4.619873046875 和实际的结果 4.62相差0.000126953125,对于一般的计算已经足够精确了;

FPGA小数乘法

计算内容

5.555*4.444=24.68642

 

第一步:将被乘数乘以256

5.555*256 = 1422.08   = 20’d1422 = 20’h5_8E;  (存在误差0.0056%)

4.444*256 = 1137.664 = 20’d1137= 20’h4_71;   (存在误差0.058%)

 

第二步:中间运算

20’h5_8E * 20’h4_71 = 20’h18_ABAE;

 

第三步:中间结果除以256

20’h18_ABAE >> 8 = 20’h18_AB;

 

第四步:转换为实际小数比较

20’h18_AB = 24.171(存在误差2%)

 

注:1、中间乘法操作时,不存在误差。

       2、如果想降低取整导致的误差,可以加大位宽

加减法运算

如果两个小数点的位置不相同,比如说分别为0△0101、00△110,代表的十进制数分别是0.3125和0.75。两个数不经过处理,直接相加,Verilog HDL的编译器按照二进制规则逐位相加,结果为01011。如果小数点位置与第一个数相同,则表示0.6875。如果小数点位置与第二个数相同,则表示1.375,显示结果是不正确的。为了进行正确的运算,需要在第二个末位补0,为00△1100,两个数再直接相加,得到“01△1001”,转换成十进制数为1.0625,得到正确的结果;

综上所述,如果对于未对齐的二进制数,需要补齐最低位使得小数位的位宽相同才能进行加减法运算;如果将数据均看成无符号整数,则不需要进行小数位扩展,因为Verilog HDL编译器会自动将参与运算的数据以最低位对齐进行运算;

module CP_3_1_alt_calculate_add
(
input [3:0] d1,
input [3:0] d2,
output [3:0] unsigned_out,   	//无符号加法输出
output signed [3:0] signed_out   //有符号加法输出


);

//无符号加法运算
assign unsigned_out=d1+d2;		

//有符号加法运算
wire signed [3:0] s_d1;
wire signed [3:0] s_d2;
assign s_d1=d1;
assign s_d2=d2;
assign signed_out=s_d1+s_d2;

endmodule

乍眼一看,我们的signed_out及unsigned_out的输出结果完全相同,相同的输入数据,进行无符号数运算和有符号数运算的结果竟然没有任何区别!对于加减法来说,无论是否为符号数运算,其结果均完全相同,因为二进制的运算规则相同,如果将二进制数据转换成十进制数据,我们就可以看出两者的差别了:

浮点数的表示方法

一个浮点数A由两个数m和e来表示,即A=m×b^e. 在任意一个这样的系统中,我们选择一个基数b(计数系统的基)和精度B(使用多少位来存储)。m(即尾数)是B位二进制数,如±d.ddd…ddd。(其中第一个d必然是1,除非你要表示特别小的数才是0)
大部分计算机采用了二进制(b=2)的表示方法,位是衡量浮点数所需存储空间的单位,通常为32位或64位,分别叫做单精度和双精度。单精度扩展(>=43位,不常用)、双精度扩展(>=79位,通常采用80位进行实现),实际上,现在很多计算机都遵循这个标准;

符号位占1bit,指数位E(Exponent)占8bit,其取值范围为0~255(无符号整数)(注意:E为无符号整数,实际数值e=E-127,这一点务必注意),尾数位M占23bit。尾数也叫做有效数字位、系数位、甚至被称作小数;

浮点数的定点化 

转成定点数要定义小数需求多少位,整数需求多少位

例:16位的定点数(MAX:16’d32767 MIN:-32768) 
3位整数位宽,12位的小数位,最高位的符号位 
取低15位,其中第14,13,12位最大能表示7, 
小数最大12位能表示的最大精度:1/4096=0.000244140625 
(0.000244140625*4095 = 0.999755859375) 
极限最大值表示:7.999755859375

 

  • 32
    点赞
  • 210
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
Verilog,可以使用FPGA来进行浮点数运算。FPGA通常使用硬件模块来实现浮点数运算,这种方式可以提高浮点数运算的速度和精度。 FPGA常用的浮点数表示方式是IEEE 754格式。IEEE 754是一种二进制浮点数表示法,它将浮点数表示为一个符号位、指数位和尾数位组成的二进制数。IEEE 754格式可以用于表示32位或64位浮点数。 在Verilog,可以使用IEEE 754格式来进行浮点数运算。Verilog可以使用浮点数类型,如real、double等,来声明浮点数变量。同时,Verilog也提供了一些内置函数来进行浮点数运算,例如加减乘除、取余等。 以下是一个简单的Verilog代码示例,展示了如何使用FPGA实现浮点数运算: ``` module float_adder(input [31:0] a, input [31:0] b, output reg [31:0] c); real ra, rb, rc; initial begin ra = $bitstoreal(a); rb = $bitstoreal(b); rc = ra + rb; c = $realtobits(rc); end endmodule ``` 在上面的代码,我们声明了三个变量:a、b和c,它们分别表示两个待加的浮点数和它们的和。我们使用real类型来声明ra、rb和rc变量。在initial块,我们将a和b转换为实数类型,然后将它们相加,最后将结果转换为32位二进制数,并将结果存储在变量c。 请注意,以上代码只是一个简单的示例,实际应用时需要根据具体情况进行修改和调整。同时,浮点数运算在FPGA的实现非常复杂,需要对硬件和算法有深入的理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值