Verilog 中對浮點數(shù)如何處理
掃描二維碼
隨時隨地手機看文章
算法中常常會到浮點數(shù)運算,而浮點數(shù)的處理常常是Verilog初學(xué)中常常遇到的問題。以下將就一個簡單的例子說明Verilog中浮點數(shù)運算處理。
在JPEG圖像壓縮時遇到色彩空間變換的問題,將YCbCr轉(zhuǎn)換到RGB會遇到浮點數(shù)的運算,這個實現(xiàn)復(fù)雜,以攝氏溫度轉(zhuǎn)換為華氏溫度為例 :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; :0] ic; :0] of; :0] c; :0] of; iclk or negedge irstn) begin 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. endendmodule
上面直接用浮點數(shù)進行乘法運算顯然是會出錯的?。?
//以下為改正后的程序
module C2F( iclk,irstn,ic,of); input iclk; input irstn; :0] ic; :0] of; :0] c; :0] of; :0] sum; iclk or negedge irstn) begin begin <= 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 endendmodule
將浮點數(shù)乘以相同的擴展倍數(shù),然后再將所得結(jié)果除以擴展位,這樣可以達到近似精確的效果?。?
謂定點小數(shù),就是小數(shù)點的位置是固定的。我們是要用整數(shù)來表示定點小數(shù),由于小數(shù)點的位置是固定的,所以就沒有必要儲存它(如果儲存了小數(shù)點的位置,那就是浮點數(shù)了)。既然沒有儲存小數(shù)點的位置,那么計算機當(dāng)然就不知道小數(shù)點的位置,所以這個小數(shù)點的位置是我們寫程序的人自己需要牢記的!
先以10進制為例:如果我們能夠計算12+34=46的話,當(dāng)然也就能夠計算1.2+3.4 或者 0.12+0.34了。所以定點小數(shù)的加減法和整數(shù)的相同,并且和小數(shù)點的位置無關(guān)。乘法就不同了。12*34=408,而1.2*3.4=4.08。這里1.2的小數(shù)點在第1位之前,而4.08的小數(shù)點在第2位之前,小數(shù)點發(fā)生了移動。所以在做乘法的時候,需要對小數(shù)點的位置進行調(diào)整?!可是既然我們是做定點小數(shù)運算,那就說小數(shù)點的位置不能動?。≡趺唇鉀Q這個矛盾呢,那就是舍棄最低位。 也就說1.2*3.4=4.1,這樣我們就得到正確的定點運算的結(jié)果了。所以在做定點小數(shù)運算的時候不僅需要牢記小數(shù)點的位置,還需要記住表達定點小數(shù)的有效位數(shù)。上面這個例子中,有效位數(shù)為2,小數(shù)點之后有一位。
現(xiàn)在進入二進制:我們的定點小數(shù)用16位二進制表達,最高位是符號位,那么有效位就是15位。小數(shù)點之后可以有0 - 15位。我們把小數(shù)點之后有n位叫做Qn,例如小數(shù)點之后有12位叫做Q12格式的定點小數(shù),而Q0就是我們所說的整數(shù)。
Q12的正數(shù)的最大值是 0 111 . 111111111111,第一個0是符號位,后面的數(shù)都是1,那么這個數(shù)是十進制的多少呢,很好運算,就是 0x7fff / 2^12 = 7.999755859375。對于Qn格式的定點小數(shù)的表達的數(shù)值就它的整數(shù)值除以2^n。在計算機中還是以整數(shù)來運算,我們把它想象成實際所表達的值的時候,進行這個運算
反過來把一個實際所要表達的值x轉(zhuǎn)換Qn型的定點小數(shù)的時候,就是x*2^n了。例如 0.2的Q12型定點小數(shù)為:0.2*2^12 = 819.2,由于這個數(shù)要用整數(shù)儲存, 所以是819 即 0x0333。因為舍棄了小數(shù)部分,所以0x0333不是精確的0.2,實際上它是819/2^12 =0.199951171875
我們用數(shù)學(xué)表達式做一下總結(jié):
x表示實際的數(shù)(一個浮點數(shù)), q表示它的Qn型定點小數(shù)(一個整數(shù))。
q = (int) (x * 2^n)
x = (float)q/2^n
由于/ 2^n和* 2^n可以簡單的用移位來計算,所以定點小數(shù)的運算比浮點小數(shù)要快得多。下面我們用一個例子來驗證一下上面的公式:
用Q12來計算2.1 * 2.2,先把2.1 2.2轉(zhuǎn)換為Q12定點小數(shù):
2.1 * 2^12 = 8601.6 = 8602
2.2 * 2^12 = 9011.2 = 9011
(8602 * 9011) >> 12 = 18923
18923的實際值是18923/2^12 = 4.619873046875 和實際的結(jié)果 4.62相差0.000126953125,對于一般的計算已經(jīng)足夠精確了;
FPGA小數(shù)乘法
計算內(nèi)容
5.555*4.444=24.68642
第一步:將被乘數(shù)乘以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;
第三步:中間結(jié)果除以256
20’h18_ABAE >> 8 = 20’h18_AB;
第四步:轉(zhuǎn)換為實際小數(shù)比較
20’h18_AB = 24.171(存在誤差2%)
注:1、中間乘法操作時,不存在誤差。
2、如果想降低取整導(dǎo)致的誤差,可以加大位寬
加減法運算
如果兩個小數(shù)點的位置不相同,比如說分別為0△0101、00△110,代表的十進制數(shù)分別是0.3125和0.75。兩個數(shù)不經(jīng)過處理,直接相加,Verilog HDL的編譯器按照二進制規(guī)則逐位相加,結(jié)果為01011。如果小數(shù)點位置與第一個數(shù)相同,則表示0.6875。如果小數(shù)點位置與第二個數(shù)相同,則表示1.375,顯示結(jié)果是不正確的。為了進行正確的運算,需要在第二個末位補0,為00△1100,兩個數(shù)再直接相加,得到“01△1001”,轉(zhuǎn)換成十進制數(shù)為1.0625,得到正確的結(jié)果;
綜上所述,如果對于未對齊的二進制數(shù),需要補齊最低位使得小數(shù)位的位寬相同才能進行加減法運算;如果將數(shù)據(jù)均看成無符號整數(shù),則不需要進行小數(shù)位擴展,因為Verilog HDL編譯器會自動將參與運算的數(shù)據(jù)以最低位對齊進行運算;
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的輸出結(jié)果完全相同,相同的輸入數(shù)據(jù),進行無符號數(shù)運算和有符號數(shù)運算的結(jié)果竟然沒有任何區(qū)別!對于加減法來說,無論是否為符號數(shù)運算,其結(jié)果均完全相同,因為二進制的運算規(guī)則相同,如果將二進制數(shù)據(jù)轉(zhuǎn)換成十進制數(shù)據(jù),我們就可以看出兩者的差別了:
浮點數(shù)的表示方法
一個浮點數(shù)A由兩個數(shù)m和e來表示,即A=m×b^e. 在任意一個這樣的系統(tǒng)中,我們選擇一個基數(shù)b(計數(shù)系統(tǒng)的基)和精度B(使用多少位來存儲)。m(即尾數(shù))是B位二進制數(shù),如±d.ddd…ddd。(其中第一個d必然是1,除非你要表示特別小的數(shù)才是0)
大部分計算機采用了二進制(b=2)的表示方法,位是衡量浮點數(shù)所需存儲空間的單位,通常為32位或64位,分別叫做單精度和雙精度。單精度擴展(>=43位,不常用)、雙精度擴展(>=79位,通常采用80位進行實現(xiàn)),實際上,現(xiàn)在很多計算機都遵循這個標(biāo)準(zhǔn);
符號位占1bit,指數(shù)位E(Exponent)占8bit,其取值范圍為0~255(無符號整數(shù))(注意:E為無符號整數(shù),實際數(shù)值e=E-127,這一點務(wù)必注意),尾數(shù)位M占23bit。尾數(shù)也叫做有效數(shù)字位、系數(shù)位、甚至被稱作小數(shù);
浮點數(shù)的定點化
轉(zhuǎn)成定點數(shù)要定義小數(shù)需求多少位,整數(shù)需求多少位
例:16位的定點數(shù)(MAX:16’d32767 MIN:-32768)
3位整數(shù)位寬,12位的小數(shù)位,最高位的符號位
取低15位,其中第14,13,12位最大能表示7,
小數(shù)最大12位能表示的最大精度:1/4096=0.000244140625
(0.000244140625*4095 = 0.999755859375)
極限最大值表示:7.999755859375





