IEEE 浮點標準:V = (-1)s * M * 2E 表示一個浮點數:html
V
的正(s=0)或負(s=1),對於 0 後面會有說明將浮點數的位分爲 3 個部分:java
以 C 語言爲例,不一樣的精度下,s、exp、frac 有不一樣的位數:api
單精度: 31 30 23 22 0 +---+---------+-----------------------------------------+ | s | exp | frac | +---+---------+-----------------------------------------+ 雙精度: 63 62 52 51 32 +---+----------------+----------------------------------+ | s | exp | frac(51:32) | +---+----------------+----------------------------------+ 31 0 +-------------------------------------------------------+ | frac(31:0) | +-------------------------------------------------------+
以 C 語言單精度爲例,根據 exp 存儲的位的不一樣,所表示的浮點數能夠分紅 3 中不一樣的狀況,而最後一種狀況中狀況分兩個變種:數組
規格化post
+-------------------------------------------------------+ | s | exp!=0 & exp!=255 | frac | +-------------------------------------------------------+這是最多見的狀況,exp 的位模式既不爲全 0,也不爲全 1
E = exp - Bias
,exp 是無符號數,Bias = 2k-1 - 1,偏置的做用是爲了在規格化取值範圍與非規格化取值範圍之間平滑過分尾數 M 的值並非 frac 所表示的小數值,實際狀況是M = 1 + frac
一般狀況下,二進制整數部分經過調整小數點(也就是修改 E)來變成 1,因此 IEEE 的表示法直接將這一位的 1
省去,這樣二進制小數部分就能多存儲一位,提升了精度,也就是說這個 frac 隱含了開頭的 1.net
舉個例子:假設 frac 有 5 位,如今要存儲一個二進制數 b,b 的值是 0.101011(2),調整一下權重:1.01011 * 2-1(2),farc 存儲的就是小數點後面的這 5 位01011
code
非規格化htm
+-------------------------------------------------------+ | s | exp=0 | frac | +-------------------------------------------------------+exp 位模式全爲 0,E = exp - Bias,M = frac
無窮大(Infinity)blog
+-------------------------------------------------------+ | s | exp=255 | frac=0 | +-------------------------------------------------------+exp 全部位皆是 1,frac 全部位皆是 0 ,表示無窮大
NaN(Not a Number)ci
+-------------------------------------------------------+ | s | exp=255 | frac!=0 | +-------------------------------------------------------+
exp 全部位皆是 1,frac 的位模式不全爲 0 ,表示 NaN 不是一個數
階碼的值決定了該浮點數是規格化的、非規格化的、無窮大或者 NaN
舉例,將 1 個 float 數據轉換爲 4Byte 的二進制數據存儲起來:
float a = 10.25F; Decimal Binary 整數部分: 10 ====> 1010 小數部分: 0.25 ====> 0.01 科學計數法: 1.025 * 10^1 ====> 1010.01 = 1.01001 * 2^3 s = 0 ====> 0 E = 3 ====> E 包含偏置,IEEE 用 0111 1111 = 2^7 - 1 = 127 來表示 E = 0,因此當 E = 3 時,二進制表示爲: 1000 0010 = 130 = 127 + 3 M = 1.01001 ====> 小數點前是 1,因此直接去掉,只保留小數部分,二進制表示爲:0100 1000 s exp frac 10.25 ====> 0 | 1000 0010 | 01001000000000000000000 ====> 0100 0001 0010 0100 0000 0000 0000 0000
須要注意的 3 個地方:
小數部分:0.25 = 1/4,即 2 的 -2 次方,也就是二進制的 1 小數點左移 2 位,因此獲得的二進制表示爲 0.01。須要注意的是:不是全部的十進制小數都能轉換爲二進制小數,好比十進制的 0.3,因此只能取近似值,經過 2^-n(n>0,n 爲整數) 來接近 0.3
階碼是有偏置的:2k-1 - 1
將給定的字節數組轉換爲對應的浮點數,JDK 中 Float 和 Double 均提供了對應的方法來處理這種狀況,以 Float 爲例,使用的方法java.lang.Float#intBitsToFloat(int bits)
,將參數 bits 的位模式解析爲浮點數,API 中的說明:
int s = ((bits >> 31) == 0) ? 1 : -1; int e = ((bits >> 23) & 0xff); int m = (e == 0) ? (bits & 0x7fffff) << 1 : (bits & 0x7fffff) | 0x800000;
浮點結果等於算術表達式 s·m·2e-150 的值
對應給定的浮點數,進行四捨五入可使用java.math.BigDecimal#setScale(int, int)
方法,能夠設定保留小數的位數,以及四捨五入的方式
class Scratch { public static void main(String[] args) { int intbis = 0B0100_0001_0010_0100_0000_0000_0000_0000; System.out.println(Integer.toBinaryString(intbis)); System.out.println(Float.intBitsToFloat(intbis)); System.out.println(Integer.toBinaryString(Float.floatToIntBits(10.25F))); } }