【STM32H7的DSP教程】第8章 DSP定點數和浮點數(重要)

完整版教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=94547

第8章   DSP定點數和浮點數(重要)

本期教程主要跟大家講解一下定點數和浮點數的基礎知識,瞭解這些基礎知識對於後面學習ARM官方的DSP庫大有裨益。特別是初學的一定要理解這些基礎知識。

目錄

第8章   DSP定點數和浮點數(重要)

8.1   初學者重要提示

8.2   定點數和浮點數概念

8.2.1  定點數

8.2.2  浮點數

8.3   IEEE浮點數

8.3.1  規範化浮點數

8.3.2  非規範化浮點數

8.3.3  有符號的零

8.3.4  無窮

8.3.5  NaN

8.4   定點數運算

8.4.1  數的定標(Q格式)

8.4.2  定點數的算術運算

8.5   總結


 

8.1   初學者重要提示

  1.   如果之前沒有接觸過這方便的知識點,首次學習會有點不太理解,隨着後面章節的深入就慢慢理解了。

8.2   定點數和浮點數概念

如果小數點的位置事先已有約定,不再改變,此類數稱爲“定點數”。相比之下,如果小數點的位置可變,則稱爲“浮點數”(定點數的本質是小數,整數只是其表現形式)。 

8.2.1  定點數

常用的定點數有兩種表示形式:如果小數點位置約定在最低數值位的後面,則該數只能是定點整數;如果小數點位置約定在最高數值位的前面,則該數只能是定點小數。

8.2.2  浮點數

在計算機系統的發展過程中,曾經提出過多種方法表達實數。典型的比如相對於浮點數的定點數(Fixed Point Number)。在這種表達方式中,小數點固定的位於實數所有數字中間的某個位置。貨幣的表達就可以使用這種方式,比如 99.00 或者 00.99 可以用於表達具有四位精度,小數點後有兩位的貨幣值。由於小數點位置固定,所以可以直接用四位數值來表達相應的數值。SQL 中的 NUMBER 數據類型就是利用定點數來定義的。還有一種提議的表達方式爲有理數表達方式,即用兩個整數的比值來表達實數。 

定點數表達法的缺點在於其形式過於僵硬,固定的小數點位置決定了固定位數的整數部分和小數部分,不利於同時表達特別大的數或者特別小的數。最終,絕大多數現代的計算機系統採納了所謂的浮點數表達方式。這種表達方式利用科學計數法來表達實數,即用一個尾數(Mantissa ),一個基數(Base),一個指數(Exponent)以及一個表示正負的符號來表達實數。比如 123.45 用十進制科學計數法可以表達爲 1.2345 × 102,其中 1.2345 爲尾數,10 爲基數,2 爲指數。浮點數利用指數達到了浮動小數點的效果,從而可以靈活地表達更大範圍的實數。

 

8.3   IEEE浮點數

說明:Cortex-M7中的FPU(浮點單元)就是用的這個IEEE 754標準,初學的要認真學習。

IEEE二進制浮點數算術標準(IEEE 754)是20世紀80年代以來最廣泛使用的浮點數運算標準,爲許多CPU浮點運算器所採用。這個標準定義了表示浮點數的格式(包括負零-0)與反常值(denormal number),一些特殊數值(無窮Inf)與非數值(NaN),以及這些數值的“浮點數運算符”;它也指明瞭四種數值舍入規則和五種例外狀況(包括例外發生的時機與處理方式)。

IEEE 754規定了四種表示浮點數值的方式:單精確度(32位)、雙精確度(64位)、延伸單精確度(43比特以上,很少使用)與延伸雙精確度(79比特以上,通常以80比特實現)。只有32位模式有強制要求,其他都是選擇性的。大部分編程語言都有提供IEEE浮點數格式與算術,但有些將其列爲非必需的。例如,IEEE 754問世之前就有的C語言,現在有包括IEEE算術,但不算作強制要求(C語言的float通常是指IEEE單精確度,而double是指雙精確度)。

該標準的全稱爲IEEE二進制浮點數算術標準(ANSI/IEEE Std 754-1985),又稱IEC 60559:1989,微處理器系統的二進制浮點數算術(本來的編號是IEC 559:1989)。後來還有“與基數無關的浮點數”的“IEEE 854-1987標準”,有規定基數爲2跟10的狀況。現在最新標準是“IEEE 854-2008標準”。

在六、七十年代,各家計算機公司的各個型號的計算機,有着千差萬別的浮點數表示,卻沒有一個業界通用的標準。這給數據交換、計算機協同工作造成了極大不便。IEEE的浮點數專業小組於七十年代末期開始醞釀浮點數的標準。在1980年,英特爾公司就推出了單片的8087浮點數協處理器,其浮點數表示法及定義的運算具有足夠的合理性、先進性,被IEEE採用作爲浮點數的標準,於1985年發佈。而在此前,這一標準的內容已在八十年代初期被各計算機公司廣泛採用,成了事實上的業界工業標準。

在 IEEE 標準中,浮點數是將特定長度的連續字節的所有二進制位分割爲特定寬度的符號域,指數域和尾數域三個域,其中保存的值分別用於表示給定二進制浮點數中的符號,指數和尾數。這樣,通過尾數和可以調節的指數(所以稱爲"浮點")就可以表達給定的數值了。具體的格式參見下面的圖例: 

  •   在上面的圖例中,第一個域爲符號域。其中 0 表示數值爲正數,而 1 則表示負數。
  •   第二個域爲指數域。其中單精度數爲 8 位,雙精度數爲 11 位。以單精度數爲例,8 位的指數爲可以表達 0 到 255 之間的 255 個指數值。但是,指數可以爲正數,也可以爲負數。

爲了處理負指數的情況,實際的指數值按要求需要加上一個偏差(Bias)值作爲保存在指數域中的值,單精度數的偏差值爲 127,而雙精度數的偏差值爲 1023。比如,單精度的實際指數值 0 在指數域中將保存爲 127;而保存在指數域中的 64 則表示實際的指數值 -63。 偏差的引入使得對於單精度數,實際可以表達的指數值的範圍就變成 -127 到 128 之間(包含兩端)。我們後面還將看到,實際的指數值 -127(保存爲 全 0)以及 +128(保存爲全 1)保留用作特殊值的處理。這樣,實際可以表達的有效指數範圍就在 -127 和 127 之間。在本文中,最小指數和最大指數分別用 emin 和 emax 來表達。

  •   圖例中的第三個域爲尾數域,其中單精度數爲 23 位長,雙精度數爲 52 位長。除了我們將要講到的某些特殊值外,IEEE 標準要求浮點數必須是規範的。這意味着尾數的小數點左側必須爲 1,因此我們在保存尾數的時候,可以省略小數點前面這個 1,從而騰出一個二進制位來保存更多的尾數。這樣我們實際上用 23 位長的尾數域表達了 24 位的尾數。比如:

對於單精度數而言,二進制的 1001.101(對應於十進制的 9.625)可以表達爲 1.001101 × 23,所以實際保存在尾數域中的值爲 0011 0100 0000 000 0000 0000,即去掉小數點左側的 1,並用 0 在右側補齊。 

值得注意的是,對於單精度數,由於我們只有 24 位的指數(其中一位隱藏),所以可以表達的最大指數爲 224 - 1 = 16,777,215。特別的,16,777,216 是偶數,所以我們可以通過將它除以 2 並相應地調整指數來保存這個數,這樣 16,777,216 同樣可以被精確的保存。相反,數值 16,777,217 則無法被精確的保存。由此,我們可以看到單精度的浮點數可以表達的十進制數值中,真正有效的數字不高於 8 位。事實上,對相對誤差的數值分析結果顯示有效的精度大約爲 7.22 位。參考下面的示例:

 

根據標準要求,無法精確保存的值必須向最接近的可保存的值進行舍入。這有點像我們熟悉的十進制的四捨五入,即不足一半則舍,一半以上(包括一半)則進。不過對於二進制浮點數而言,還多一條規矩,就是當需要舍入的值剛好是一半時,不是簡單地進,而是在前後兩個等距接近的可保存的值中,取其中最後一位有效數字爲零者。從上面的示例中可以看出,奇數都被舍入爲偶數,且有舍有進。我們可以將這種舍入誤差理解爲"半位"的誤差。所以,爲了避免 7.22 對很多人造成的困惑,有些文章經常以 7.5 位來說明單精度浮點數的精度問題。 

提示: 這裏採用的浮點數舍入規則有時被稱爲舍入到偶數(Round to Even)。相比簡單地逢一半則進的舍入規則,舍入到偶數有助於從某些角度減小計算中產生的舍入誤差累積問題。因此爲 IEEE 標準所採用。 

8.3.1  規範化浮點數

通過前面的介紹,大家應該已經瞭解的浮點數的基本知識,這些知識對於一個不接觸浮點數應用的人應該足夠了。簡單總結如下:

標準的浮點數都符都符合如下的公式:

其中bias是固定的數值,這個在前面的已經講解過。參數的具體範圍如下

 

8.3.2  非規範化浮點數

我們來考察浮點數的一個特殊情況。選擇兩個絕對值極小的浮點數,以單精度的二進制浮點數爲例,比如 1.001 × 2-125和 1.0001 ×2-125 這兩個數(分別對應於十進制的 2.6448623 × 10-38和 2.4979255 ×10-38)。顯然,他們都是普通的浮點數(指數爲 -125,大於允許的最小值 -126;尾數更沒問題),按照 IEEE 754 可以分別保存爲 00000001000100000000000000000000(0x1100000)和 00000001000010000000000000000000(0x1080000)。 

現在我們看看這兩個浮點數的差值。不難得出,該差值爲 0.0001 × 2-125,表達爲規範浮點數則爲 1.0 × 2-129。問題在於其指數大於允許的最小指數值,所以無法保存爲規範浮點數。最終,只能近似爲零(Flush to Zero)。這中特殊情況意味着下面本來十分可靠的代碼也可能出現問題: 

if (x != y)

{ 

z = 1 / (x -y); 

} 

正如我們精心選擇的兩個浮點數展現的問題一樣,即使 x 不等於 y,x 和 y 的差值仍然可能絕對值過小,而近似爲零,導致除以 0 的情況發生。

爲了解決此類問題,IEEE 標準中引入了非規範(Denormalized)浮點數。規定當浮點數的指數爲允許的最小指數值,即 emin 時,尾數不必是規範化的。比如上面例子中的差值可以表達爲非規範的浮點數 0.001 × 2-126,其中指數 -126 等於 emin。注意,這裏規定的是"不必",這也就意味着"可以"。當浮點數實際的指數爲 emin,且指數域也爲 emin 時,該浮點數仍是規範的,也就是說,保存時隱含着一個隱藏的尾數位。爲了保存非規範浮點數,IEEE 標準採用了類似處理特殊值零時所採用的辦法,即用特殊的指數域值 emin - 1 加以標記,當然,此時的尾數域不能爲零。這樣,例子中的差值可以保存爲 00000000000100000000000000000000(0x100000),沒有隱含的尾數位。

有了非規範浮點數,去掉了隱含的尾數位的制約,可以保存絕對值更小的浮點數。而且,也由於不再受到隱含尾數域的制約,上述關於極小差值的問題也不存在了,因爲所有可以保存的浮點數之間的差值同樣可以保存。

8.3.3  有符號的零

因爲 IEEE 標準的浮點數格式中,小數點左側的 1 是隱藏的,而零顯然需要尾數必須是零。所以,零也就無法直接用這種格式表達而只能特殊處理。 

實際上,零保存爲尾數域爲全爲 0,指數域爲 emin - 1 = -127,也就是說指數域也全爲 0。考慮到符號域的作用,所以存在着兩個零,即 +0 和 -0。不同於正負無窮之間是有序的,IEEE 標準規定正負零是相等的。

零有正負之分,的確非常容易讓人困惑。這一點是基於數值分析的多種考慮,經利弊權衡後形成的結果。有符號的零可以避免運算中,特別是涉及無窮的運算中,符號信息的丟失。舉例而言,如果零無符號,則等式 1/(1/x) = x 當x = ±∞ 時不再成立。原因是如果零無符號,1 和正負無窮的比值爲同一個零,然後 1 與 0 的比值爲正無窮,符號沒有了。解決這個問題,除非無窮也沒有符號。但是無窮的符號表達了上溢發生在數軸的哪一側,這個信息顯然是不能不要的。零有符號也造成了其它問題,比如當 x=y 時,等式1/x = 1/y 在 x 和 y 分別爲 +0 和 -0 時,兩端分別爲正無窮和負無窮而不再成立。當然,解決這個問題的另一個思路是和無窮一樣,規定零也是有序的。但是,如果零是有序的,則即使 if (x==0) 這樣簡單的判斷也由於 x 可能是 ±0 而變得不確定了。兩害取其輕者,零還是無序的好。

8.3.4  無窮

和 NaN 一樣,特殊值無窮(Infinity)的指數部分同樣爲 emax + 1 = 128,不過無窮的尾數域必須爲零。無窮用於表達計算中產生的上溢(Overflow)問題。比如兩個極大的數相乘時,儘管兩個操作數本身可以用保存爲浮點數,但其結果可能大到無法保存爲浮點數,而必須進行舍入。根據 IEEE 標準,此時不是將結果舍入爲可以保存的最大的浮點數(因爲這個數可能離實際的結果相差太遠而毫無意義),而是將其舍入爲無窮。對於負數結果也是如此,只不過此時舍入爲負無窮,也就是說符號域爲 1 的無窮。有了 NaN 的經驗我們不難理解,特殊值無窮使得計算中發生的上溢錯誤不必以終止運算爲結果。

無窮和除 NaN 以外的其它浮點數一樣是有序的,從小到大依次爲負無窮,負的有窮非零值,正負零(隨後介紹),正的有窮非零值以及正無窮。除 NaN 以外的任何非零值除以零,結果都將是無窮,而符號則由作爲除數的零的符號決定。

當零除以零時得到的結果不是無窮而是 NaN 。原因不難理解,當除數和被除數都逼近於零時,其商可能爲任何值,所以 IEEE 標準決定此時用 NaN 作爲商比較合適。 

8.3.5  NaN

NaN 用於處理計算中出現的錯誤情況,比如 0.0 除以 0.0 或者求負數的平方根。由上面的表中可以看出,對於單精度浮點數,NaN 表示爲指數爲 emax + 1 = 128(指數域全爲 1),且尾數域不等於零的浮點數。IEEE 標準沒有要求具體的尾數域,所以 NaN 實際上不是一個,而是一族。不同的實現可以自由選擇尾數域的值來表達 NaN。

8.4   定點數運算

8.4.1  數的定標(Q格式)

在許多情況下,數學運算過程中的數不一定都是整數,而且定點DSP和不帶FPU的處理器是無能爲力的。那麼是不是說定點DSP和不帶FPU的處理器就不能處理各種小數呢?當然不是。這其中的關鍵就是由程序員來確定一個數的小數點處於數據中的哪一位。這就是數的定標(由於很多時候,我們都是直接用C來實現浮點運算,具體的底層轉化我們並沒有去關心,所以也就很少有人知道數的定標)。

通過設定小數點在數據中的不同位置,就可以表示不同大小和不同精度的小數了。數的定標有Q表示法和S表示法兩種。下表列出了一個16位數的16種Q表示、S表示及它們所能表示的十進制數值範圍。

 

從上表可以看出,同樣一個16位數,若小數點設定的位置不同,它所表示的數也就不同。例如,

         16進制數2000H=8192,用Q0表示

         16進制數2000H=0.25,用Q15表示

還可以看出,不同的Q所表示的數不僅範圍不同,而且精度也不相同。Q越大,數值範圍越小,但精度越高;相反,Q越小,數值範圍越大,但精度就越低。例如,Q0 的數值範圍是-32768到+32767,其精度爲1,而Q15的數值範圍爲-1到0.9999695,精度爲1/32768=0.00003051。因此,對定點數而言,數值範圍與精度是一對矛盾,一個變量要想能夠表示比較大的數值範圍,必須以犧牲精度爲代價;而想精度提高,則數的表示範圍就相應地減小。在實際的定點算法中,爲了達到最佳的性能,必須充分考慮到這一點。

浮點數與定點數的轉換關係可表示爲:

 

例如,浮點數x=0.5,定標Q=15,則定點數xq=L0.5*32768J=16384,式中LJ表示下取整。反之,一個用Q=15表示的定點數16384,其浮點數爲16384 *2^-15=16384/32768=0.5。浮點數轉換爲定點數時,爲了降低截尾誤差,在取整前可以先加上0.5。

8.4.2  定點數的算術運算

關於定點數的算術運算會在講解ARM官方的DSP教程時專門給大家講解。

8.5   總結

本期教程就跟大家講這麼多,這部分知識對於初學DSP的非常重要,建議認真學習下,有興趣的可以在網上多查些資料進行了解。

 

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