第一部分:fpga內部計算小數
第二部分:fpga小數乘法
第一部分:fpga內部計算小數
來自:謂定點小數,就是小數點的位置是固定的。我們是要用整數來表示定點小數,由於小數點的位置是固定的,所以就沒有必要儲存它(如果儲存了小數點的位置,那就是浮點數了)。既然沒有儲存小數點的位置,那麼計算機當然就不知道小數點的位置,所以這個小數點的位置是我們寫程式的人自己需要牢記的。
先以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可以簡單的用移位來計算,所以定點小數的運算比浮點小數要快得多。下面我們用乙個例子來驗證一下上面的公式:假設q1,q2,q3表達的值分別為x1,x2,x3
q3 = q1 + q2 若 x3 = x1 + x2
q3 = q1 - q2 若 x3 = x1 - x2
q3 = q1 * q2 / 2^n若 x3 = x1 * x2
q3 = q1 * 2^n / q2若 x3 = x1 / x2
我們看到加減法和一般的整數運算相同,而乘除法的時候,為了使得結果的小數點位不移動,對數值進行了移動。
用c語言來寫定點小數的乘法就是:
short q1,q2,q3;
....
q3=((long q1) * (long q2)) >> 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小數乘法
來自:
經常有人問, fpga裡小數乘法怎麼搞?
如果你樂意, 按照ieee754標準做」浮點」型運算的ip當然最好(雖然面積上不太好).
不過,很多情況下,沒有這個必要.
一般我們就用」定點」了.
你得自己」定個點」, 比如用16位, 分成8位整數8位小數(後面記為」(8.8)」), 即」定點」在第8位.
那麼:1 -> 16』h0100;
1.5 -> 1.5*256 = 384 -&t ; 16』h0180;
-1.5 -> -1.5*256 + 65536(補碼) -> 16』hfe80(其實就是-16』sh0180, 讓綜合器給我們算補碼去~~);
1.164 -> 1.164*256 = 298 = 16』h012a;
所以 signed input [15:0] a (也是」8整.8小」)和 1.164相乘給 signed output [15:0] mul (也是」8整.8小」), 直接寫:
assign mul = (a * 16』sh012a) >>>8;
就行了, 當然, 你的fpga裡有dsp block最好, 不然也要幾百個le的.
因為 (8.8) 乘 (8.8) 得到 (16.16), 為了恢復成 (8.8), 所以帯符號右移8位即可.
把低8位小數捨掉, 高8位整數也丟了, 所以你得保證你的16位(8.8)的」定點小數」乘積不能超過範圍, 多數數字訊號處理係數都是區間[-1.0, 1.0]的,多半不存在問題, 積分什麼的, 還有其它可能有問題的自己想清楚就行, 當然你要保留16位整.16位小也可以~~~
總結:module fixpmul
parameter iw = 8,
parameter fw = 8
)(input signed [iw+fw-1 : 0] a,
input signed [iw+fw-1 : 0] b,
output signed [iw+fw-1 : 0] o
);(* multstyle = 「dsp」 *) wire signed [iw*2+fw*2-1 : 0] long;
assign long = a * b;
assign o = long >>> fw;
endmodule
ps: 作為乙個完美主義者的想法: 以8位整型為例, 其實 8位有符號 乘 8位有符號得到的 16位有符號, 中的第14位(權2^14的位, 符號位右邊的位), 很討厭, 它只有在 -128 * -128時才等於1, 其它65535種情況, 全是0, 很浪費.
所以我們一般在數字訊號處理系統中, 永遠把[-1,1]對映到[-127,127], 這樣那個討厭的第14位永遠用不到, 然後就可以: wire signed [15:0] mul = a * b; wire signed [14:0] out = , 8位有符號 乘 8位有符號 得到 15位有符號, 節約一位.
第三部分:我的整理及應用
計算內容(8位整數8位小數)
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、如果想降低取整導致的誤差,可以加大位寬。
Verilog表示小數 定點小數
最近博主搞fpga影象處理,由於用作三維成像那麼精度必不可少啊,但是verilog又不像c等高階語言一樣,我隨便設個double就可以賦值啊啥的,那麼咋辦,定點小數就孕育而生了。當然verilog也可以用浮點數表示,這裡博主就不提及了。何謂定點小數,顧名思義,就是小數字後的數目固定,即精度固定,這裡...
數位電路的基礎知識(結合Verilog)
1.數制與編碼 1.1格雷碼 1.2二進位製碼和格雷碼的相互轉換 1.2.1二進位製碼轉換為格雷碼 1.2.2格雷碼轉換為二進位製碼 2.邏輯代數 3.硬體描述語言 verilog 關於reg和wire的使用以及alway a,b 在verilog中想要表示乙個二進位制,首先要給出二進位制的長度,其...
C 基礎知識整理 基礎知識(2) 類
類,是物件導向語言的基礎。類的三大特性 封裝 繼承 多型。最基本的特性就是封裝性。程式設計師用程式描述世界,將世界的所有事物都看成物件,怎麼描述這個物件?那就是類了。也就是用類來封裝物件。用書上的話說,類是具有相同屬性和行為的物件的抽象。寶馬汽車 別克汽車 五菱之光汽車.基本具有相同的屬性和行為,所...