verilog中對浮點數的處理

原文鏈接:http://www.cnblogs.com/woshitianma/archive/2013/05/19/3087258.htm

算法中常常會到浮點數運算,而浮點數的處理常常是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、如果想降低取整導致的誤差,可以加大位寬

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章