淩宇 在www.360doc.com中轉帖【IEEE浮點數標記法】,經過仔細研究,終於有點心得了。
float轉十六進位:
16進位浮點數的表示方法,根據IEEE的標準,分為32位和64位兩種,參數分別如下:
|
符號位 |
指數位 |
指數位移量 |
尾數位 |
32位 |
1[31] |
8[23-30] |
23[0-22] |
127 |
64位 |
1[63] |
11[52-62] |
52[0-51] |
1023 |
float
共計32位,摺合4位元組
由最高到最低位分別是第31、30、29、……、0位
31位是符號位,1表示該數為負,0反之。
30-23位,一共8位是指數位。
22-0位,一共23位是尾數位。
現在讓我們按照IEEE浮點數標記法,一步步的將float型浮點數123456.0f轉換為十六進位代碼。
在處理這種不帶小數的浮點數時,直接將整數部轉化為二進位表示:1 11100010 01000000。
也可以這樣表示:11110001001000000.0。
然後將小數點向左移,一直移到離最高位只有1位,就是最高位的1:1.11100010010000000。
一共移動了16位,在布耳運算中小數點每向左移一位就等於在以2為底的科學計演算法表示中指數+1,所以原數就等於這樣:1.11100010010000000 * ( 2 ^ 16 )。
好了,現在我們要的尾數和指數都出來了。顯而易見,最高位永遠是1,因為你不可能把買了16個雞蛋說成是買了0016個雞蛋吧?所以這個1我們還有必要保留他嗎?好的,我們刪掉他。
這樣尾數的二進位就變成了:11100010010000000最後在尾數的後面補0,一直到補夠23位:11100010010000000000000。
再回來看指數,一共8位,可以表示範圍是0 - 255的不帶正負號的整數,也可以表示-128 - 127的有符號整數。
但因為指數是可以為負的,所以為了統一把十進位的整數化為二進位時,都先加上127,在這裡,我們的16加上127後就變成了143,二進位表示為:10001111。
12345.0f這個數是正的,所以符號位是0,那麼我們按照前面講的格式把它拼起來:
0 10001111 11100010010000000000000
01000111 11110001 00100000 00000000
再轉化為16進位為:47 F1 20 00,最後把它翻過來,就成了:00 20 F1 47。
==========================================================
按照IEEE浮點數標記法,將float型浮點數123.456f轉換為十六進位代碼。
整數部直接化二進位:100100011。
小數部的處理比較麻煩一些。
來看一下步驟:1 / 2 ^1位(為了方便,下面僅用2的指數來表示位),
第1位:0.456小於位階值0.5故為0;
2位,0.456大於位階值0.25,該位為1,並將0.45減去0.25得0.206進下一位;
3位,0.206大於位階值0.125,該位為1,並將0.206減去0.125得0.081進下一位;
4位,0.081大於0.0625,為1,並將0.081減去0.0625得0.0185進下一位;
5位0.0185小於0.03125,為0……
===========================
//得到浮點尾數二進位
double d = 0.0d; double d1 =0.456; StringBuilder sb = new StringBuilder(); for (int i = 1; i < 19; i++) { d = Math.pow(2,- i); if(d1<d){ sb.append(0); }else { sb.append(1); d1 = d1 - d; } } System.out.println(sb.toString());
==================================
問題出來了,即使超過尾數的最大長度23位也除不盡!這就是著名的浮點數精度問題了。不過我在這裡不是要給大家講《數值計算》,用各種方法來提高計算精度,因為那太龐雜了,恐怕我講上一年也理不清個頭緒啊。我在這裡就僅把浮點數標記法講清楚便達到目的了。
反正最後一直求也求不盡,加上前面的整數部算夠24位就行了:1111011.01110100101111001。某BC問:“不是23位嗎?”我:“倒,不是說過了要把第一個1去掉嗎?當然要加一位嘍!”
現在開始向左移小數點,大家和我一起移,眾:“1、2、3……”好了,一共移了6位,6加上127得133(怎麼跟教小學生似的?呵呵~),二進位表示為:10000101,符號位為……再……
不說了,越說越囉嗦,大家自己看吧:
0 10000101 11101101110100101111001
42 F6 E9 79
32位浮點數(123.456)在記憶體中如果儲存為 79 E9 F6 42。
則先將其到序 42 F6 E9 79使其高位在前;
再將其轉化為二進位:0 10000101 11101101110100101111001
最高位是符號位 0表示是正值;
接下來8位是指數位
轉換為十進位再減127 結果6;
尾數部分右移6位111011.01110100101111001;
最前面添1 變為1111011.01110100101111001;
整數部分為1111011 轉為十進位123;
小數部分01110100101111001;
其中0對應2的-1次方,接下來的1對應2的-2次方:
即0*2(-1)+1*2(-2)+1*2(-3)+1*2(-4)+0*2(-5)+1*2(-6)......≈ 0.456
最後相加接近於0。456
結果123.456
==========================================================
Java 程式:
System.out.println("將 123.456F 浮點數轉換成16進位:");System.out.println("十進位位:"+Float.floatToIntBits(123.456f));System.out.println("十進位位轉二進位:"+Integer.toBinaryString(Float.floatToIntBits(123.456f)));String string = Integer.toHexString(Float.floatToIntBits(123.456f)).toUpperCase();System.out.println("十六進位:"+string);System.out.println("十六進位轉換成10進位位:"+Integer.parseInt(string, 16));System.out.println("十進位浮點數:"+Float.intBitsToFloat(Integer.parseInt(string, 16)));
===============================================================