必威电竞|足球世界杯竞猜平台

單精度數
來源:互聯網

單精度數是指帶小數點實數,有效值為7位。在內存中占用4個字節(32位)。

單精度數通常以指數形式(科學記數法)來表示,以“E”或“e”來表示指數部分,如1.45e一3或1.45E一3表示0.00145。

存儲格式

符號位S(sign) - 1bit

0代表正號,1代表負號。(+0、-0視為相同?(歡迎補充資料)) +0是0000 0000

-0是1111 1111 用-128代替 它沒有反碼和補碼。

指數位E(exponent) - 8bit

E的取值范圍為0-255(無符號整數),雙精度為11位,擴張型大于等于15位,實際數值e=E-127。

有時E也稱為“移碼”,或稱為“階碼”

尾數位M(mantissa) - 23bit

M也叫有效數字位(significant)、系數位(coefficient),甚至被稱作“小數”。

在一般情況下,m=(1.M)2,使得實際起作用范圍為1≤尾數<2。

為了對溢出進行處理,以及擴展對接近0的極小數值的處理能力,IEEE 754對M做了一些額外規定,參見后文介紹。

浮點數

對于內部存儲數據(00111111)2:

符號位

(最左側)S=0。這表示是個正數

指數

(左側第2-9位)E=(01111110)2=(126)10,所以e=E-127=-1。

尾數

(最后的23位)M=(11001100110)2,m=(1.M)2=(1.7999999523162841796875)10

該二進制小數轉為10進制的計算方式為1 + (1/2+1/4) + (1/32+1/64) + (1/512+1/1024)……

實際值

N=1.7999999523162841796875*2^-1=0.89999997615814208984375

(其實,這個數據是0.9的單精度浮點數的實際內部存儲,可以看到有一定的誤差)

這里繼續給出另外幾個數字的實例:

使用豎線|將各個段位分隔顯示

實際值 | 符號位 | ;指數 | ;尾數

1 |

2 |

-6.5 | 1 | 10000001 | 10100000000

表示范圍

最大表示范圍:單精度浮點數可以表示的范圍為±3.40282 * 10^38(

1.1111...1×2^127)

接近于0的最小值:單精度浮點數可以表示1.175 * 10-38(1.00...0×2^-126)的數據而不損失精度。

當數值比以上值小的時候,將會由于尾數的有效位數減少而逐步喪失精度(IEEE 754的規定),或者有的系統則直接采用0值來簡化處理過程。

精度

單精度浮點數的實際有效精度為24位二進制,這相當于 24*log102≈7.2 位10進制的精度,所以平時我們說“單精度浮點數具有7位精度”。(精度的理解:當從1.000...02變化為1.000...12時,變動范圍為2^23,考慮到因為四舍五入而得到的1倍精度提高,所以單精度浮點數可以反映2^24的數值變化,即24位二進制精度)

誤差

浮點數以有限的32bit長度來反映無限的實數集合,因此大多數情況下都是一個近似值。同時,對于浮點數的運算還同時伴有誤差擴散現象。

特定精度下看似相等的兩個浮點數可能并不相等,因為它們的最小有效位數不同。

由于浮點數可能無法精確近似于十進制數,如果使用十進制數,則使用浮點數的數學或比較運算可能不會產生相同的結果。

如果涉及浮點數,值可能不往返。值的往返是指,某個運算將原始浮點數轉換為另一種格式,而反向運算又將轉換后的格式轉換回浮點數,且最終浮點數與原始浮點數相等。由于一個或多個最低有效位可能在轉換中丟失或更改,往返可能會失敗。

標準格式

單精度浮點數用4字節存儲,雙精度浮點數用8字節存儲,分為三個部分:符號位、階和尾數。階即指數,尾數即有效小數位數。單精度格式階占8位,尾數占24位,符號位1位,雙精度則為11為階,53位尾數和1位符號位。

細心的人會發現,單雙精度各部分所占字節數量比實際存儲格式多了一位,的確是這樣,事實是,尾數部分包括了一位隱藏位,允許只存儲23位就可以表示24位尾數,默認的1位是規格化浮點數的第一位,當規格化一個浮點數時,總是調整它使其值大于等于1而小于2,亦即個位總是為1。例如1100B,對其規格化的結果為1.1乘以2的三次方,但個位1并不存儲在23位尾數部分內,這個1是默認位。

階以移碼的形式存儲。對于單精度浮點數,偏移量為127(7FH),而雙精度的偏移量為1023(3FFH)。存儲浮點數的階碼之前,偏移量要先加到階碼上。前面例子中,階為2的三次方,在單精度浮點數中,移碼后的結果為127+3即130(82H),雙精度為1026(402H)。

浮點數有兩個例外。數0.0存儲為全零。無限大數的階碼存儲為全1,尾數部分全零。符號位指示正無窮或者負無窮。

下面舉幾個例子:

單精度浮點數

十進制;規格化;符號;移階碼 尾數

-12 -1.1x2^3 1 1000001

0.25 1.0x2^-2 0 01111101

所有字節在內存中的排列順序,英特爾的cpu按little endian順序,motorola的cpu按big endian順序排列。

更多規范

0值

以指數E、尾數M全零來表示0值。當指數位S變化時,實際存在“正0”和“負0”兩個內部表示,其值認為都等于0。

接近于0的數值

當指數E為0時,IEEE 754規定:m=(0.M)2 e=-126。通過這個規則,將擴大對0值附近數據的表示能力。

幾個實例:

符號S 指數E 尾數M 代表意義 對應10進制 相對誤差 0 00000000.12*2-126 5.87e-39 2-23

000000000 0.012*2-126 2.94e-39 2-22

…… ;…… ;…… ;……

.0000...12*2-126=2-148 2.80e-45 50%

0 1.40e-45 100%

(注:部分系統不支持此類數據,而直接進行0值處理)

存儲變形

單精度浮點數應用廣泛,而一些低成本的單片機系統中不具備數學運算的協處理器硬件,因而在在不同系統中,根據硬件特性對浮點數的軟件實現進行了相應調整和簡化。

存在如下一些IEEE 754常見變形:

高低位的字節順序不同

即高字節在先的big endian和低字節在先的little endian。后者在英特爾、Motorola等的CPU中大量使用。

指數部分被單獨存為一字節

獨立字節比較便于處理。此類系統會把符號位與尾數結合起來存放。

此外,不同系統中對于下列特性可能有細微差異:

無窮大、NaN的規定和處理

這可能會影響到溢出特性

非歸一化數據的處理

有可能為了簡單,而將無法歸一化的小數值直接以0來處理;有的則直接采用(0.M)2方案表示全域尾數,以犧牲1位二進制精度的代價換取算法的同意。

以上兩部分的改變,對大多數的應用情形影響不大。

無窮大

當指數E為全1時,IEEE 754規定此類存儲作為特別使用,而不是普通數據。

無窮大

E=255 M=0時,用作無窮大(或Infinity、∞)。根據符號不同,又有+∞、-∞。

無窮大可以由算術運算得出,下面是有關無窮大的幾個運算示例:

1/∞ = 0,-1/∞ = -0,1/0 = ∞,-1/0 = -∞

NaN

E=255、M不為0時,用作NaN(Not a Number,“不是數”之意)。

當對數據進行非法運算(例如對-1開平方)時,結果出現NaN。

運算時含有NaN時,結果也必定是NaN。

注意:NaN<>NaN!對NaN進行相互比較是無意義的。

(NaN還有QNaN和SNaN的用法,用于程序捕獲某些例外狀態。參見NaN條目)

雙精度

簡介

單精度和雙精度數值類型最早出現在c語言中(比較通用的語言里面),在C語言中單精度類型稱為浮點類型(float),顧名思義是通過浮動小數點來實現數據的存儲。這兩個數據類型最早是為了科學計算而產生的,他能夠給科學計算提供足夠高的精度來存儲對于精度要求比較高的數值。

但是與此同時,他也完全符合科學計算中對于數值的觀念:

當我們比較兩個棍子的長度的時候,一種方法是并排放著比較一下,一種方法是分別量出長度。但是事實上世界上并不存在兩根完全一樣長的棍子,我們測量的長度精度受到人類目測能力和測量工具精度的限制。從這個意義上來說,判斷兩根棍子是否一樣長絲毫沒有意義,因為結果一定是False,但是我們可以比較他們兩個哪個更長或者更短。這個例子很好地概括了單精度/雙精度數值類型的設計初衷和存在意義。

基于上述認識,單精度/雙精度數值類型從一開始設計的時候,就不是一個準確的數值類型,他只保證在他這個數值類型的精度之內是準確的,精度之外則不保證,比方說,一個數值5.1,很可能存儲在單精度/雙精度數值中的實際值是5.1或者5.09999999999999。導致這個現象的原因我們可以通過兩種方式來解釋。

解釋方法

你可以嘗試在任何一個控件的屬性面板中,設定他的寬度為:3.2CM,當你輸入完畢后,你會發現值自動變成了3.199cm,無論你怎么改,你都無法輸入3.200CM,因為實際上在電腦中存儲的并不是CM為單位的數值,而是“”為單位的數值,而“緹”和CM之間的比值,是個很難被除盡的數,因此你輸入完畢后,電腦自動轉換成了最接近的“緹”值,然后再轉換成厘米顯示到屬性面板上,這一乘一除,兩次四舍五入,誤差就出來了。單精度/雙精度也是類似的原理,其實在二進制存儲的時候,單精度/雙精度都采用了類似相近分數的方法,而這樣的存儲是不可能做到準確的。

深入解釋

讓我們來看看我們存儲到數字介質中的單精度/雙精度值到底是怎么樣的,我們使用如下代碼對單精度類型進行一個解剖:

Public Declare Sub CopyMemory 天秤座 "kernel32" Alias "RTL GroupMoveMemory" (Destination As Any,Source As Any,ByVAL Length As Long)

Public Sub floatTest()

Dim dblVar As Single

dblVar = 5.731 / 8

dblOutput dblVar

dblVar = dblVar * 2

dblOutput dblVar

dblVar = dblVar * 2

dblOutput dblVar

dblVar = dblVar * 2

dblOutput dblVar

dblVar = dblVar * 2

dblOutput dblVar

dblVar = dblVar * 2

dblOutput dblVar

End Sub

Public Sub dblOutput(ByVal dblVar As Single)

Dim bytVar⑶As 字節

Dim i As Integer,j As Integer

Dim strVar As String

CopyMemory ByVal VarPtr(bytVar(0)),ByVal VarPtr(dblVar),4

strVar = dblVar & ": "

For i = 3 To 0 Step -1

For j = 7 To 0 Step -1

strVar = strVar & (bytVar(i) And 2 ^ j) / 2 ^ j

樂華七子NEXT j

strVar = strVar & " "

NeXT i

Debug.Print strVar

End Sub

運行后我們得到輸出結果(輸出格式為高位左,低位右):

.716375: 00111111

⒈43275: 00111111 1

⒉8655: 01000000 0

⒌731: 01011010

⒒462: 01000001 0

22.924: 01000001 1

這里,我們把單精度類型轉化成了二進制數據輸出,這里我們看到,雖然這六個數字完全不同,但是它們的二進制存儲驚人地相似,我們看到紅色標記部分,每次都是加1,事實上,單精度數據類型使用從高位開始第1位作為正負標記位(綠色),第2位到第9位,是一個跨字節的有符號字節類型數據,這個數值決定了小數點移動的方向和位數(紅色),第10位到32位保存一個整數(藍色)在存儲過程中,電腦首先把輸入的值不斷移位(乘除2)直到這個數的整數部分占用了全部24位的整數位,然后把移動的位數寫入浮點部分(紅色),而移位后的結果寫入整數部分(藍色和綠色),小數部分則舍棄。求值的時候則是反向過程,先根據正負位和整數位求值,然后根據紅色部分的整數來進行移位(乘除2的次方),最終才是我們得到的單精度數值。雙精度數值也是同樣原理,只是位數更多而已。

評價

通過解剖單精度數值的二進制存儲格式,我們可以清楚看到,實際上單精度/雙精度的存儲,都要通過乘法和除法,其中必有舍入,如果恰好你的數值在除法中被舍入了,那么你賦的初值就很可能與你最終存儲的值不完全相同,其中的微小差異,并不與單精度/雙精度的設計目標相違背。

當我們在數據庫中或者Visual Basic for Applications代碼中使用一個單精度/雙精度數值的時候,也許你從界面上看不到區別,但是在實際的存儲中,這個差別卻真真切切地就在那里,當你對其進行相等比較的時候,系統只是簡單地作二進制的比較,界面上無法體現的微小差異,在二進制比較面前卻無處遁形,于是,你的等于比較返回了一個意料之外的False。

參考資料 >

生活家百科家居網