浮點數的各種最值推算以及對python sys.float_info的解釋

目錄

最大和最小的正規約數取值

最小和最大的正非規約數取值

浮點數能在該範圍內精確表示的最大十進制整數

大於1的最小規約數和1之間的距離epsilon

對python sys.float_info的解釋


       本文將以64位浮點數爲例,對64位浮點數的取值範圍進行推算,並通過python的sys.float_info的信息,對其逐一解釋,以對浮點數有一個更好的理解。本文需要筆者的這篇文章作爲預備知識。

最大和最小的正規約數取值

       對於64位整數來說,由於規約數的移碼後的指數取值範圍爲(1~2046)-1023=(-1022~1023),所以移碼後的指數最小值爲-1022,最大值爲1023,對應着最小正規約數和最大正規約數的指數取值情形;對於尾數來說,自然就是當尾數小數部分全部爲0和全部爲1時,分別取到最小值和最大值,因此根據分析,我們可以通過如下代碼進行二進制到十進制的最小最大值的推算。

s = '1'*53+'0'*(1023-52)
f_max = float(int(s,2))
[out]:
1.7976931348623157e+308

f_min = float(1/int('1'*1022,2))
[out]:
2.2250738585072014e-308

 

如上代碼所示,最大規約數的二進制表示就是隱藏的首位1加52位尾數的1=53個1,然後剩下1023-52位的0,最後通過int函數將該二進制數轉爲十進制,就可以得到十進制的最大的規約數。同理,對於最小正規約數,就是當尾數全部爲0,首位爲1,指數爲-1022時的二進制數,同樣經過int函數轉爲十進制數,得到十進制的最小正規約數。

最小和最大的正非規約數取值

       根據非規約數的定義,即指數爲0,尾數小數不全爲0的數,這時首位的隱藏爲也變成了0,不再是1,而且移碼後的指數保持-1022不變。所以,最小的非規約數就是當尾數的小數部分最後一位爲1,其他位全部爲0的時候;由於這時移碼後的指數依然爲-1022,所以可由如下代碼推算得到。同理,最大的非規約數就是當尾數首位隱藏位爲0,其他52位小數全部爲1時的數,注意這時的指數爲-1022。如下所示。

f_subnormal_min = float(1/(2**(1022+52)))
f_subnormal_min
[out]:
5e-324

f_subnormal_max = float(int('1'*52,2)/(2**(1022+52)))
f_subnormal_max
[out]:
2.225073858507201e-308

f_min - f_subnormal_max #注意f_subnormal_min + f_subnormal_max剛好等於f_min
[out]:
5e-324

浮點數能在該範圍內精確表示的最大十進制整數

       由於64位浮點數的尾數只有53位(52位加上一位隱藏位),所以如果某個十進制整數轉爲64位浮點數後,其二進制的位數超過了53位,那麼這個整數的精度就會丟失,所以知道浮點數可以精確表示最大的十進制整數是很重要的,可以避免因爲精度問題造成數據的錯誤。自然地,該十進制整數只需要通過53位全爲1的二進制數反推回去就可以得到,如下所示。

max_int = int('1'*53,2)
print(max_int)
[out]:
9007199254740991 #該數就是64位浮點數可以精確表示的最大十進制整數

       所以,只要一個整數小於等於這個數,那麼一定可以保證,當一個整數轉爲64位浮點數時,該整數還是原來那個數,精度不會丟失,但是如果大於這個數,那麼精度就無法保證了。

大於1的最小規約數和1之間的距離epsilon

       這個數很簡單,即第52位爲1,其他全爲0,且移碼後的指數爲0,注意不要忽略了隱藏的首位1。所以其和1之間的就是二進制下的0.000....0001,其中小數點後面的0共有51個,由此可以計算得到其和1之間的差epsilon,如下所示。

epsilon = float(1/int('1'*52,2))
print(epsilon)
[out]:
2.2204460492503136e-16

對python sys.float_info的解釋

print(sys.float_info)
[out]:
sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)

       其中max表示的就是最大的規約數,上面已經進行了推算;radix表示的是在電腦中儲存的基數,即進制數,這裏表明的是二進制(很顯然);max_exp表示的是使得radix**(e-1)爲可表示的有限浮點數最大指數,根據上述,由於移碼後的規約數的指數範圍爲-1022~1023,即最大爲1023,所以最大的e自然就是1024;max_10_exp表示的是讓10**e爲一個可表示的浮點數最大的指數,同樣的,根據上面對最大規約數的推導,計算得到的結果爲1.7976931348623157e+308,所以max_10_exp自然就是308;min表示最小的正規約數,這個和上面的推導結果也是一致的;min_exp表示的是使得radix**(e-1)爲可表示的有限浮點數最小指數,因爲移碼後的最小指數爲-1022(儘管指數爲0時,我們設定此時偏移量爲1022,所以移碼後的指數依然爲-1022),因此最小的e爲-1021;min_10_exp表示的是讓10**e爲一個可表示的規約浮點數最小的指數,由於計算得到的最小規約數爲2.2250738585072014e-308,所以這時最小的e爲-307(要注意不是-308,因爲10**(-308)比最小正規約數2.2250738585072014e-308還小,這是不符合要求的,所以應該是-307);dig表示可以保證被精確的轉爲浮點數的整數的數字個數,因爲我們上面計算得到的可以保證被精確的轉爲浮點數的整數應該小於等於9007199254740991,該數有16位數字,但是大於該數的16位數字的整數是無法被精確的轉爲浮點數的,所以能夠被保證可以精確表示成64位浮點數的整數的最大位數應該爲15;mant_dig就是mantissa digits,即尾數位數,由於我們知道尾數的首位1是被隱藏的,所以真正的尾數位數共有52位小數位數加上首位的隱藏1,共有53位;這裏的epsilon和我們上面說的epsilon意義一樣,就是最小的大於1的浮點數和1之間的差值;radix表示基數,也就是進制數,這裏指的是二進制;最後rounds表示的是當一個整數轉成浮點數,對無法精確表示的整數的近似模式,這裏爲1表示的是取裏原值最近的浮點表示,如果存在兩種不同的表示距離一樣近,那麼去最後一位(即第52位bit)爲0的情形,對rounds的說明可以具體看筆者的下一篇文章

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