目錄
- 1.前言
- 2.研究數字表示法的意義
- 3.數字表示法
- 3.1 無符號整數
- 3.2 有符號數值
- 3.3 二進制補碼(Two's Complement, 2C)
- 3.4 二進制反碼(也稱作 1 的補碼, One's Complement, 1C)
- 3.5 減 1 表示法(Diminished one System, D1)
- 3.6 原碼、反碼、補碼總結
1.前言
昨天有粉絲讓我講解下定點數和浮點數,本來這部分是打算在FPGA入門系列的最后面來講的。作者想開的系列真的很多,比如開發FPGA需要學會相關軟件Matlab、Vivado、ModelSim等等的使用,每個軟件做一個系列;FPGA入門教程做一個系列;基礎數字信號處理做一個系列;通信相關的系列;IP核使用詳解系列;FPGA數字積木系列(自己設計的一些參數化IP)。但是這些無疑都會花大量的時間去構思和整理資料,會出的比較慢,請讀者耐心等待。
這篇文章就先介紹定點數和浮點數的概念,因為要真正講清楚還得從原碼、補碼和反碼開始講起。要仔細研究的建議去多看看相關書籍,講清楚原理之后再講Matlab里面計算的浮點數怎么轉換為定點數到FPGA里面進行使用,以及FPGA里面計算的定點數,怎么在Matlab里面又轉換為浮點數。
這里需要重點強調的是,原理雖然很枯燥,但是真的很重要,是絕對不能忽視的,如果原理弄的一知半解,就開始去做處理,后期該踩得坑一個也少不了。
2.研究數字表示法的意義
在計算機算法中,有兩個基本設計準則是非常重要的:分別是數字表示法和代數運算的實現。例如:定點數或浮點數就是常用且可行的數字表示法。一些基本的運算,像加法器和乘法器,更為繁瑣的運算,諸如求平方根和應用CORDIC算法計算角函數的有效實現,都要以可行的數字表示法為基礎實現。
FPGA由于其物理位級編程結構的特點,提供了大量實現數字信號處理算法所需要的計算機算法。這恰好與帶有定點多級累加器內核的可編程數字信號處理器(programmable digital signal processors,PDSP)相反。在FPGA設計中仔細地選擇位寬就能夠從本質上做到節約。
3.數字表示法
在工程的早期階段,必須仔細考慮,確定是使用定點數還是浮點數更適合于解決問題。一般可以認為:定點數的實現具有更高的速度和更低廉的成本;而浮點數則具有更高的動態范圍且不需要換算,這對較為復雜的算法可能更適合。下圖給出了傳統和非傳統定點數和浮點數的數字表示法的一個概觀。兩套系統都由許多各自的標準所覆蓋,當然,如果需要的話也可以以一種專有形式實現。
3.1 無符號整數
設 X X X 是 一個 N N N 位無符號二進制數, 則其范圍是 [ 0 , 2 N ? 1 ] \left[0,2^N-1\right] [0,2N?1], 表達式如下:
X = ∑ n = 0 N ? 1 x n 2 n X=\sum_{n=0}^{N-1} x_n 2^n X=n=0∑N?1?xn?2n
其中 x n x_n xn? 是 X X X 的第 n n n 位二進制數字(也就是 x n ∈ [ 0 , 1 ] x_n \in[0,1] xn?∈[0,1] )。數字 x 0 x_0 x0? 稱作最低有效位(Least Significant Bit, LSB), 具有相當于個位的權重。數字 x N ? 1 x_{N-1} xN?1? 就是最高有效位(Most Significant Bit, MSB), 具有相當于 2 N ? 1 2^{N-1} 2N?1 的權重。
3.2 有符號數值
在有符號數字表示法中, 數字和符號是單獨表示的。第一位代表符號, 余下的 N ? 1 N-1 N?1 位代表數字, 表達式如下:
X = { ∑ n = 0 N ? 1 x n 2 n X ≥ 0 ? ∑ n = 0 N ? 1 x n 2 n X < 0 X= \begin{cases}\sum_{n=0}^{N-1} x_n 2^n & X \geq 0 \\ -\sum_{n=0}^{N-1} x_n 2^n & X<0\end{cases} X={∑n=0N?1?xn?2n?∑n=0N?1?xn?2n?X≥0X<0?
表達式的范圍是 [ ? 2 N ? 1 , 2 N ? 1 ] \left[-2^{N-1}, 2^{N-1}\right] [?2N?1,2N?1], 有符號數字表示法的優點就是簡化了溢出的問題, 但缺點就是加法需要根據哪一個操作數更大來進行區分運算。
3.3 二進制補碼(Two’s Complement, 2C)
有符號整數的 N N N 位二進制補碼表達式如下:
X = { ∑ ∞ ? 0 N ? 1 x n 2 n X ≥ 0 2 k ? ∑ n = 0 1 ? 1 x n 2 n X < 0 X= \begin{cases}\sum_{\infty-0}^{N-1} x_n 2^n & X \geq 0 \\ 2^k-\sum_{n=0}^{1-1} x_n 2^n & X<0\end{cases} X={∑∞?0N?1?xn?2n2k?∑n=01?1?xn?2n?X≥0X<0?
其范圍是 [ ? 2 N ? 1 , 2 N ? 1 ? 1 ] \left[-2^{N-1}, 2^{N-1}-1\right] [?2N?1,2N?1?1]。目前數字信號處理領域,最常用的就是用二進制補碼來表示有符號數。這是由于它可以累加多個有符號數,且最終結果也在N位范圍內,即可以忽略一切算術上的溢出。
例如,我們計算兩個3位數的差(3-2=?):
3 10 ? 01 1 2 C ? 2 10 ? 11 0 2 C 1 10 ? 1.00 1 2 C \begin{array}{rrr} 3_{10} & \leftrightarrow & 011_{2 C} \\ -2_{10} & \leftrightarrow & 110_{2 C} \\ 1_{10} & \leftrightarrow & 1.001_{2 C} \end{array} 310??210?110??????0112C?1102C?1.0012C??
溢出可以忽略。所有的計算都是取模 2 N 2^N 2N 。這樣就有可能出現不能夠正確表示中間值的情形,但只要最終值有效, 結果就是正確的。例如計算 3 位的數字 2 + 2 ? 3 2+2-3 2+2?3, 會得到一個中間值 010 + 010 = 10 0 2 C 010+010=100_{2 C} 010+010=1002C?, 也就是 ? 4 10 -4_{10} ?410?, 但是結果 100 ? 011 = 100 + 101 = 00 1 2 C 100-011=100+101=001_{2 C} 100?011=100+101=0012C?, 是正確的。
二進制補碼還可以用來實現模 2 N 2^N 2N 的算法, 而且不需要在算法中作任何改動。
3.4 二進制反碼(也稱作 1 的補碼, One’s Complement, 1C)
N N N 位二進制反碼數字表示法可以表示的整數范圍是 [ ? 2 N ? 1 ? 1 , 2 N ? 1 ? 1 ] \left[-2^{N-1}-1,2^{N-1}-1\right] [?2N?1?1,2N?1?1] 。在二進制反碼中,正整數和負整數除了符號位之外具有相同的表示方法。那么“0”就有正的和負的,兩個表達式。二進制反碼中有符號數的標準表達式如下:
X = { ∑ n = 0 N ? 1 x n 2 n X ≥ 0 2 N ? 1 ? ∑ n = 0 N ? 1 x n 2 n X < 0 X= \begin{cases}\sum_{n=0}^{N-1} x_n 2^n & X \geq 0 \\ 2^N-1-\sum_{n=0}^{N-1} x_n 2^n & X<0\end{cases} X={∑n=0N?1?xn?2n2N?1?∑n=0N?1?xn?2n?X≥0X<0?
請看下面的簡單示例:
3 10 ? 0 1 1 1 C ? 2 10 ? 1 0 1 1 C 1 10 ? 1. 0 0 0 1 C 進位 → → → 1 1 C 1 10 ? 0 0 1 1 C \begin{array}{rrrrrr} 3_{10} & \leftrightarrow & & 0 & 1 & 1_{1 C} \\ -2_{10} & \leftrightarrow & & 1 & 0 & 1_{1 C} \\ 1_{10} & \leftrightarrow & 1. & 0 & 0 & 0_{1 C} \\ 進位 & & \rightarrow & \rightarrow & \rightarrow & 1_{1 C} \\ 1_{10} & \leftrightarrow & & 0 & 0 & 1_{1 C} \end{array} 310??210?110?進位110???????1.→?010→0?100→0?11C?11C?01C?11C?11C??
在二進制反碼中需要, “進位問繞(carry wrap-around)” 加法。在最高有效位與最低有效位相加得到正確結果時, 就會出現進位。
盡管如此, 這種數字表示法還走能夠有效地實現模 2 N ? 1 2^N-1 2N?1 運算, 而且不需要校正。因此二進制反碼在實現特定的 DSP 算法(例如: 整數計算不 2 N ? 1 2^N-1 2N?1 的 Mersenne 變換)時, 還是有其特殊價值的。
3.5 減 1 表示法(Diminished one System, D1)
減1表示法是一種有偏移的數學表示法。正整數與二.進制補碼相比減少了 1。 N N N 位 D1數值范圍是 [ ? 2 N ? 1 , 2 N ? 1 ] ( \left[-2^{N-1}, 2^{N-1}\right]( [?2N?1,2N?1]( 不含 0 ) ) ) 。D1 數字表示法的編碼規則定義如下:
X = { ∑ n = 0 A ? 1 x n 2 n ? 1 X ≥ 0 2 N ? ∑ n = 0 N ? 1 x n 2 n X < 0 2 N X = 0 X= \begin{cases}\sum_{n=0}^{A-1} x_n 2^n-1 & X \geq 0 \\ 2^N-\sum_{n=0}^{N-1} x_n 2^n & X<0 \\ 2^N & X=0\end{cases} X=? ? ??∑n=0A?1?xn?2n?12N?∑n=0N?1?xn?2n2N?X≥0X<0X=0?
從下面兩個 D1 數相加可以看到, 對于 D1 而言還必須計算補碼和顛倒進位的加法。
3 10 ? 0 1 0 D 1 ? 2 10 ? 1 1 0 D 1 1 10 ? 1. 0 0 0 D 1 進位 → .?-1 → 0 D 1 1 10 ? 0 0 0 D 1 \begin{array}{rrrrrr} 3_{10} & \leftrightarrow & & 0 & 1 & 0_{D 1} \\ -2_{10} & \leftrightarrow & & 1 & 1 & 0_{D 1} \\ 1_{10} & \leftrightarrow & 1. & 0 & 0 & 0_{D 1} \\ 進位 & & \rightarrow &\fbox{. -1} & \rightarrow & 0_{D 1} \\ 1_{10} & \leftrightarrow & & 0 & 0 & 0_{D 1} \end{array} 310??210?110?進位110???????1.→?010.?-1?0?110→0?0D1?0D1?0D1?0D1?0D1??
D1 數不需要在算法上作任何改動就能夠有效地實現模 2 N + 1 2^N+1 2N+1 運算。比如可以利用這一結論在 2 N + 1 2^N+1 2N+1 計算環中實現費爾出 NTT(Fermat Network Transfer Table, Fermat 網絡傳輸表)。
3.6 原碼、反碼、補碼總結
上面說了這么多,又是公式又是例子的估計很多人都開始暈了,現在直接總結口訣如下:
對于有符號數而言:
1.二進制的最高位是符號位:0表示正數,1表示負數(口訣0——>0,1——>-)。
2.正數的原碼、反碼、補碼都是一樣的(三碼合一)。
3.負數的反碼 = 它的原碼符號位不變,其他位取反(0——>1,1——>0)。
4.負數的補碼 = 它的反碼 + 1,負數的反碼 = 負數的補碼 - 1。
5.0的反碼、補碼都是0。
6.在計算機運算的時候,都是以補碼的方式來運算的。
7.當我們看運算結果的時候,要看它的原碼。
關注微信公眾號獲取更多資訊:????![在這里插入圖片描述](https://img-