浮點

浮點

浮點型簡單講就是實數的意思。浮點數在計算機中用以近似表示任意某個實數。具體的說,這個實數由一個整數或定點數(即尾數)乘以某個基數(計算機中通常是2)的整數次冪得到,這種表示方法類似於基數為10的科學記數法。

浮點計算

浮點計算是指浮點數參與浮點計算的運算,這種運算通常伴隨著因為無法精確表示而進行的近似或捨入。

一個浮點數a由兩個數m和e來表示:a = m × b^e(b的e次方)。在任意一個這樣的系統中,我們選擇一個基數b(記數系統的基)和精度p(即使用多少位來存儲)。m(即尾數)是形如±d.ddd...ddd的p位數(每一位是一個介於0到b-1之間的整數,包括0和b-1)。如果m的第一位是非0整數,m稱作規格化的。有一些描述使用一個單獨的符號位(s 代表+或者-)來表示正負,這樣m必須是正的。e是指數。

這種設計可以在某個固定長度的存儲空間內表示定點數無法表示的更大範圍的數。

舉例說明

例如,一個指數範圍為±4的4位十進制浮點數可以用來表示43210,4.321或0.0004321,但是沒有足夠的精度來表示432.123和43212.3(必須近似為432.1和43210)。當然,實際使用的位數通常遠大於4。

此外,浮點數表示法通常還包括一些特別的數值:+∞和−∞(正負無窮大)以及NaN('Not a Number')。無窮大用於數太大而無法表示的時候,NaN則指示非法操作或者無法定義的結果。

大部分計算機採用二進制(b=2)的表示方法。位(bit)是衡量浮點數所需存儲空間的單位,通常為32位或64位,分別被叫作單精度和雙精度。有一些計算機提供更大的浮點數,例如英特爾公司的浮點運算單元Intel8087協處理器(以及其被集成進x86處理器中的後代產品)提供80位長的浮點數,用於存儲浮點運算的中間結果。還有一些系統提供128位的浮點數

標準保存

以下內容需要知道二進制小數轉換十進制計算方法和整數一樣,都是對每一位用2的冪加權。

IEEE浮點標準用 V = (-1)^s * M * 2^E的形式表示

V就是值

符號(sign)s決定正負,對於0有特殊處理

有效數(significand)M是一個二進制小數,範圍在1~2或0~1之間

指數(exponent)E是2的冪(可以是負數),對浮點數加權

浮點數劃分成3個域

一個單獨符號位編碼s

k位指數域 exp = e(k-1)...e⑴e(0)編碼指數E

n位小數域 frac = f(n-1)...f⑴f(0)編碼有效數M,但被編碼的值依賴於指數域是否為零。

在C/C++中的float下 s有1位,exp有k=8位,frac有n=23位,double變數下k=11,n=52

根據exp的值,編碼分三種狀況:

規格化值

最普遍的狀況,當exp的位模式既不是全為0也不是全為1時,就都屬於這種狀況。此時,指數域解釋為偏置形式,E = e-Bias(e減Bias),e是無符號數,而Bias是一個等於2^(k-1) -1的偏置值。由此產生了指數的取值範圍,float: -126~127,double: -1022~1023

小數域解釋為描述小數值f,在0~1之間,有效數定義為M = 1+f,這樣隱含了開頭的1,免費獲得了一個額外的精度位

非規格值

指數域全為0,就是非規格化的值,此時,指數值是 E = 1 - Bias(Bias定義同上),有效數的值是 M = f,沒有開頭的1。值得注意的是這種方法對0的表示。+0.0的浮點表示中,位模式全為0:符號位是0,指數域全0,小數域也是0。而-0.0隻有符號位是1,其他全0

特殊值

指數域全為1,就是這類數。

當小數域全為0時,得到的值表示無窮,s=0正無窮,s=1負無窮。當這兩個非常大的數相乘或對某數除以0可以得到溢出的結果。當小數域非0時結果被稱作NaN,即not a number。一些運算結果不能表示為無窮或實數,就返回NaN,例如對-1開根號。

數值舉例

以8位浮點舉例,32位和64位的以此類推

0的表示:位表示0 0000 000(符號位,指數位,小數位,下同), e=0,E=1-7=-6,f=0,M=0,V=0

最小的非規格化數:(不考慮負數)

位表示 0 0000 001 此時 e=0; E=-6; f= 1/8; M=1/8; V = 1/512

即 f = 0*2^(-1)+0*2^(-2)+0*2^(-3)

V = f * 2^E

最大的非規格化數

位表示0 0000 111 表示 7/512

最小的規格化數

位表示0 0001 000

e=1; E= e - Bias = 1-7=-6; f = 0; M = 1+f = 1

V= M * 2^E = 8/512

最大的規格化數

位表示0 1110 111

e=14; E= 14-7=7; f=7/8; M = 15/8; V = 240

對於雙精度浮點

最小規格化數 2.2*10^-308 = 1*2^-1022

最大規格化數 1.8*10^308 = (2-epsilon)*2^1023

數字分布

作者:concreteHAM

什麼是浮點數,不用我多說,這裡我們要討論的是規格化的任意進制浮點數的前導數字的機率分布。

在《電腦程式設計藝術》第二卷中做了非常深入的討論,這裡我從中精煉出要點。

例如:

⒉345 E 67

這是一個十進制規格化浮點數,前導數字就是2。

就只有一個“隨機”的浮點數而言,討論其分散式沒有意義的,我們要討論的是充分多個“隨機”數進行的一系列運算後產生的浮點結果的前導數字分布。

假設現在有一巨大的浮點數集,依此對數集中每個浮點數都乘以2,其中有一個十進制浮點數F,它的前導數字是1,那么它底數可能的值範圍就是1.000…~1.999…,乘以一個數字2,那么它的底數就變成2.000…~3.999…,很明顯乘以2以前前導數字是1的浮點個數與現在前導數字是2、3的浮點個數相同。以此我們接下來分析。

對於一個b進制的浮點數,它的前導數字x範圍就是0 < x < b,設f(x)是上述數集的前導數字的機率密度函式(註:是密度函式),那么它在前導數字u和v之間(0<u<v<b)的機率就是:

∫[u,v]f(x)dx ⑴

由前面所述的,對於一個小增量Δx,f(x)必須滿足這樣一個公式:

f⑴Δx = x*f(x)Δx ⑵

很明顯:

f(x) = f⑴/x ⑶

兩邊在[1,b]之間進行積分,等號左邊必定為1,右邊等於f⑴ln(b):

1 = f⑴ln(b) ⑷

得:f⑴= 1/ln(b) 帶入⑶中:

f(x) = 1/(x*ln(b))

那么利用⑴式得:

∫[u,v]1/(x*ln(b))dx

= ln(v/u) / ln(b)

這就是求前導數字的機率分布函式。

例如b = 10進制時,前導數字為1的機率就是:

= ln((1+1)/1) / ln⑽

≈ 0.301

前導數字為9的機率就是:

= ln((9+1)/9) / ln⑽

≈0.0458

以下是一個測試程式(Mathematica軟體):

T[n_,b_]:=Block[{res={},ran,i,a},

For[i=1,i<b,i++;

res=Append[res,0]

];

For[i=0,i<n,i++;

ran=Random[]*Random[]*Random[]; 充分打亂模擬實際運算中的浮點數

ran=Log[b,ran];

a=Floor[b^(ran-Floor[ran])]; 取出前導數字

res[[a]]++ 對前導數字個數統計

];

Return[res]

]

執行T[100000,10],以10進制測試100000個浮點數,得到一個分布:

{30149,18821,13317,9674,7688,6256,5306,4655,4134}

和理論值相當接近。

關於如何取出前導數字如下:

設原浮點數為a*10^e >= 0

其中a為底數範圍(-10,-1]∪[1,10),e為指數,此時我們分離出底數部分和指數部分。

我們先對數求以10為底的對數從而分離出指數部分:

lg(a*10^e)=lg(a)+lg(10^e)=e+lg(a),因為a∈[1,10),所以lg(a)∈[0,1),而lg(10^e)=e是整數,所以lg(a*10^e)∈[e,e+1),因此我們可以通過向負無窮方向取整,也就是說取小於等於lg(a*10^e)的最大整數,lg(a)的值就等於lg(a*10^e)的值減去它取整後的數就可以了,10^(lg(a))也就是底數a,a像負無窮取整就是前導數字,如何得到e就不用多說了很簡單。

相關詞條

相關搜尋

熱門詞條

聯絡我們