科學計數(shù)法
你可能不了解「浮點數(shù)」,但你一定了解「科學記數(shù)法」。
10進制科學記數(shù)法把一個數(shù)表示成a與10的n次冪相乘的形式(1≤|a|<10,a不為分數(shù)形式,n為整數(shù)),例如:
19970000000000 = 1.997 × 10 ^ 13
原本的 19970000000000 表示共需要14位。使用科學計數(shù)法后,小數(shù)部分 1.997 的表示需要4位,指數(shù)部分 13 需要2位,則一共只需要 4+2 = 6 位即可表示這個原本看上去很多很長的數(shù)。
小數(shù)也可以使用科學計數(shù)法來表示,例如:
0.0000001586 = 1.586 × 10 ^ -7
原本的 0.0000001586 表示共需要11位。使用科學計數(shù)法后,小數(shù)部分 1.586 的表示需要4位,指數(shù)部分 -7 需要2位(符號位也占一位),則一共只需要 4+2 = 6 位即可表示該數(shù)。
設想我們現(xiàn)在設計了這么一種格式,它表示的是一種10進制的科學計數(shù)法。為了說明簡單,我們不考慮指數(shù)為負數(shù)和數(shù)值為負數(shù)的情況。它一共有8位,每一位都由10進制數(shù)字0~9組成,前6位表示小數(shù)部分,后2位表示指數(shù)部分。例如:
數(shù)字 12345603 ,它表示的值是 1.23456 × 10 ^ 3 = 1234.56
數(shù)字 12345678 ,它表示的值是 1.23456 × 10 ^ 78 = (一個很大的數(shù))
所以,當我們要表示或運算某個較大或較小且位數(shù)較多的數(shù)時,用科學記數(shù)法會更加方便。
在關于定點數(shù)的這篇文章《什么是定點數(shù)?》中,我們談到了什么是「定點數(shù)」。簡而言之,定點數(shù)就是小數(shù)點表示固定的數(shù)。那么對應的,「浮點數(shù)」是不是就是小數(shù)點不固定?是浮動的?
恭喜你答對了。
「浮點數(shù)」一詞,來自英文「float point number」,即「浮動小數(shù)點的數(shù)」。和上面所說的科學計數(shù)法類似,它們的小數(shù)點位置都是浮動的。
和10進制的科學計數(shù)法一樣,2進制數(shù)也可以表示成類似的形式,例如:
101.875(D) = 1100101.111(B) = 1.100101111 * 2^6
所以只需要約定好一定的位數(shù)來表示小數(shù)部分,一定的位數(shù)來表示指數(shù)部分,就可以完整地表示一個二進制數(shù)。如何定義這些細節(jié)是個傷腦筋的問題,而且要命的是,如果我定義的標準和同事的標準不一致,那么該聽誰的?
好在IEEE(電氣與電子工程師協(xié)會,Institute of Electrical and Electronics Engineers)幫我們把這些工作都給做了,現(xiàn)在通用的浮點數(shù)算術標準是「IEEE 754」。
浮點數(shù)格式
IEEE 754 規(guī)定了兩種常用的浮點數(shù)格式:
單精度型,也叫32位型,或者float
雙精度型,也叫64位型,或者double
因為這兩種格式的表示規(guī)則是類似的,只是位寬不一樣,了解了其中一種后,就可以快速掌握另一種,所以下文主要介紹 float 類型的浮點數(shù)表示方法。
float類型
float 占用 32 位的存儲空間,32 位被分為了如下的三個部分:
符號位s:sign,符號位為 0 說明該浮點數(shù)為正數(shù),若為 1 則說明浮點數(shù)為負數(shù)
階碼E:exponent,代表該浮點數(shù)被二進制科學表示法規(guī)范化后的指數(shù),階碼采用移碼表示
尾數(shù)M:mantissa,被二進制規(guī)約化后要求小數(shù)點前一位數(shù)必須為 1,所以尾數(shù)中實際隱含了最高位 1,例如尾數(shù)為 M,則實際在還原時,相當于是 1.M
(1)關于尾數(shù)M
尾數(shù)是用來表示精度的,因為一個數(shù)的表示其實是有多種方法的,例如:
314(D) = 3.14 × 10 ^ 2 = 31.4 × 10 ^ 1
1011(B) = 1.011 × 2 ^ 3 = 10.11 × 2 ^ 2 = 101.1 × 2 ^ 1
所以需要對小數(shù)部分的表示做出規(guī)定,為此標準規(guī)定小數(shù)部分需要簡化到「小數(shù)點左邊只有一位非0數(shù)」的形式。即規(guī)定:
314(D) 只能表示為 3.14 × 10 ^ 2 ,而不能表示為 31.4 × 10 ^ 1 或其他形式
1011(B) 只能表示為 1.011 × 2 ^ 3 ,而不能表示為 10.11 × 2 ^ 2,也不能表示為 101.1 × 2 ^ 1 或其他形式
因為10進制的非0數(shù)有1~9共9個,所以小數(shù)點最左邊這位是不能省略掉的;但是2進制數(shù)的非0數(shù)只有1這個,所以小數(shù)點最左邊的非0位可以被省略,例如:
1011(B) = 1.011 × 2 ^ 3 ,小數(shù)部分雖然為1.011,但是可以省略為.011,即011
這樣就可以多表示一位信息。float的尾部部分(即小數(shù)部分)定義了23位,因為省略了一個最前面的 1 ,所以它是表示的其實是24位信息。
(2)關于階碼E
階碼是用來表示范圍的。float定義了8位數(shù)的階碼,所以它的表示范圍是0~256(2的256次方)。這種定義有個問題就是無法表示負指數(shù),將其定義為有符號數(shù)是個不錯的解決辦法,但隨之而來的問題是–比較兩個階碼時不方便。
做兩個有符號數(shù)的某些運算(例如加法)時,首先需要比較二者的階碼大小,然后對其中一個數(shù)的階碼和尾數(shù)進行調整。例如:
計算 (3.14 × 10 ^ 2) + (1.56 × 10 ^ 3)的值時,首先需要比較二者的階碼大小,然后對其中一個數(shù)進行調整,將(1.56 × 10 ^ 3)重新表示為(15.6 × 10 ^ 2),然后尾數(shù)部分相加 3.14 + 15.6 = 15.914,即結果為15.914 × 10 ^ 3,再調整階碼將其規(guī)范化,15.914 × 10 ^ 3 = 1.5914 × 10 ^ 4
可以看到,運算其中一個重要的環(huán)節(jié)就是對兩個數(shù)的階碼大小進行對比。如果2個階碼是一正一負,那么對比二者的大小還需要考慮符號位,這樣就會增加額外邏輯。如果將階碼都加上同一個數(shù),使二者均為正數(shù),那么對比大小就方便很多了。
標準是這樣規(guī)定的:階碼的值需要加一個偏移量 127 (至于為什么移127不移128,我也不清楚,如果你知道可以告訴我)。例如:
1.011 × 2 ^ 3的原始階碼是3,按規(guī)定加上127后等于130,存儲到8位空間,即為 1000 0010
光說不練云玩家,接下來看看如何實現(xiàn)浮點數(shù)與10進制數(shù)之間的轉換。
(1)將10進制數(shù)轉換為float類型的浮點數(shù)
將 228 轉換為浮點數(shù)的流程如下:
是正數(shù),即符號位為0
把10進制轉成2進制:228(D)=11100100(B)
寫成規(guī)范化形式:11100100 = 1.11001 × 2 ^ 7
指數(shù)為7,階碼要加上偏移量127,即E = 7 + 127 = 134(D)= 1000 0110(B)
小數(shù)部分為1.11001,最前面的1是可以被隱含表示的,所以尾數(shù)M = 0.11001 = 11001,因為尾數(shù)一共有23位,所以需要在低位補0直到滿足位寬要求,即 11001000000000000000000
最終結果為:0 10000110 11001000000000000000000
這里有一個浮點數(shù)轉換網站,可以查詢正確結果。
(2)將float類型的浮點數(shù)轉換為10進制數(shù)
將 40490000 (16進制)轉換為10進制數(shù)的流程如下:
將其轉換為2進制,40490000 = 0100 0000 0100 1001 0000 0000 0000 0000,然后分別獲取符號、階碼和尾數(shù)。
最高位的符號位為0,說明是一個正數(shù)
接下來的8位是階碼 10000000(即128),因為加上了偏移量127,所以指數(shù)的實際值是128 - 127 = 1。
剩余的23位是尾數(shù)10010010000000000000000,即0.1001001,再加上默認的前導1,所以小數(shù)部分的值為1+0.1001001 = 1.1001001
該數(shù)的2進制值為 1.1001001 × 2 ^ 1 = 11.001001,將其轉化成10進制數(shù)11.001001(B)= 3. 140625。(這里的轉化有個簡便方法,11.001001可以看做是11001001除以2的6次方即64,而11001001也就是201,即201/64 = 3.140625 )
這是網站轉換的結果,和我們換算的結果一致。
double類型
double占用 64 位的存儲空間,64 位被分為了如下的三個部分:
這三部分的定義是和float類型一致的,只是位寬不同。需要注意的是,由于位寬的變化,所以double的階碼的偏移值不再是127,而是 1023。
除了這兩種較為常用的類型外,其實IEEE754還規(guī)定了幾種其他類型,但是都不太常用,所以不贅述了。
非規(guī)約化
當階碼E不全為0,也不全為1時,該浮點數(shù)稱為規(guī)約化(normal)形式。上面介紹的都是規(guī)約化形式的浮點數(shù)。當階碼E全為0時,該浮點數(shù)稱為非規(guī)約化(subnormal)形式。根據尾數(shù)的不同,可再分為2種形式:
尾數(shù)M為全 0 時,表示 0 ,視符號位而定是+0還是-0(二者在某些場景有區(qū)別)
尾數(shù)M不全為 0 時,表示非規(guī)約化小數(shù)
非規(guī)約化小數(shù)的定義和規(guī)約化小數(shù)之間存在如下區(qū)別:
規(guī)約化小數(shù)的尾數(shù)約定了含有一個隱藏的前導1,也就說真正表示的值是1.xxx;而非規(guī)約化小數(shù)的尾數(shù)則約定含有一個隱藏的前導0,即真正的值為0.xxx。
規(guī)約化小數(shù)的階碼需要加一個偏移量127,而非規(guī)約化小數(shù)的階碼需要加一個偏移量 126
非規(guī)約化小數(shù)可以用來表示那些非常小的接近0的數(shù)。
特殊值
除此之外,還規(guī)定了一些特殊值的表示方法:
如果階碼為全1,且尾數(shù)為全0時,表示無窮。符號位為0則是正無窮,符號位為1則是負無窮。兩個很大的數(shù)相乘,或者除以零時,無窮可以表示 溢出 的結果。
如果階碼為全1,且尾數(shù)不為全0時,為NaN(not a number),表示這不是一個合法實數(shù)。一些運算的結果不是合法值,就會返回NaN這樣的結果,例如對-1開平方(√-1)
對于以上情況(針對float類型),可以總結如下:
-
FPGA
+關注
關注
1625文章
21636瀏覽量
601315 -
浮點數(shù)
+關注
關注
0文章
60瀏覽量
15857 -
float
+關注
關注
0文章
9瀏覽量
7766
原文標題:基于FPGA的數(shù)字信號處理——浮點數(shù)?
文章出處:【微信號:Hack電子,微信公眾號:Hack電子】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論