您好,登錄后才能下訂單哦!
首先,將10進制的小數0.1轉換為二進制,方法如下:
0.1*2==0.2 取0.2的整數部分, 結果為0.0
0.2*2==0.4 取0.4的整數部分, 結果為0.00
0.4*2==0.8 取0.8的整數部分, 結果為0.000
0.8*2==1.6 取1.6的整數部分, 結果為0.0001
0.6*2==1.2 取1.6的整數部分, 結果為0.00011
0.2*2==0.4 取0.4的整數部分, 結果為0.000110
最后這一步開始循環,因此0.1的二進制為數為: 0.0001100110011...是一個無限循環小數,二進制數據無法精確表示.
當然,有些小數是不循環的,可以用二進制數據精確表示,如10進制的0.5轉換為轉換為二進制:
0.5*2=1.0 取1.0的整數部分, 結果為0.1
0.0*2=0.0 取0.0的整數部分, 結果為0.10
再進行運算下去,可以認為0.5的二進制數據為0.10000...,也就是1.0,不是循環小數.
可見,按照上面的運算方法,運算結果不為0且循環的時候則是無限循環小數,運算結果為0,則不是循序小數.
下面是幾個二進制小數和10進制小數對應關系:
0.1 == 0*2^1 + 1*2^-1 == 1/2 == 0.5 == 0*10^1 + 5*10^-1
0.01 == 0*2^1 + 0*2^-1 + 1*2^-2 == 0.25 == 0*10^1 + 2*10^-1 + 5*10^-2
0.001 == 0*2^1 + 0*2^-1 + 0*2^-2 + 1*2^-3 == 1/8 == 0.125 == 0*10^1 + 1*10^-1 + 2*10^-2 + 5*10^-3
0.0001 == 0*2^1 + 0*2^-1 + 0*2^-2 + 0*2^-3 + 1*10^-4 == 1*2^-4 == 1/16 == 0.0625 == 0*10^1 + 0*10^-1 + 6*10^-2 + 2*10^-3 + 5*10^-4
... ...
從這幾個對應關系可以看出二進制和十進制本質是一樣的,用科學計數法來表示: 1*2^-m+...1*2^-n
那么,小數如何在內存中存儲呢? 以float fpi=0.1415926為例說明
第一步: 將十進制的0.141593轉換為二進制數為: 0.001000011111101101001101000100...已經舍去了一部分
第二步: 將第一步的二進制小數點向右移動3位: 1.000011111101101001101000100 * 2^-3
第三步: 計算階碼,提取第二步中的指數-3,然后計算階碼: -3 + 127 == 124,124(小于127,說明是一個負數)的二進制數為: 1111 100,用8位表示就是0 1111 100
第四步: 獲取尾數,將第二步中的1.000011111101101001101000100-1=000011111101101001101000100
第五步: 將第四步的獲取的結果舍掉多余的部分,僅保留高23位: 0000111111011010011010
第六步: 將第3,5步的結果拼接到一塊,并加上符號位(正號0): (符號)0 (階碼)01111100 (尾數)0000111111011010011010
浮點數0.1415926在內存中存儲的二進制數為: 0 01111100 0000111111011010011010
如果小數帶整數部分,如3.1415926,轉換過程差不過:
1.分別將整數和小數轉換為二進制數: 011.001000011111101101001101000100
2.將第1步中的二進制數小數點向左移動1位: 1.1001000011111101101001101000100
3.計算階碼,提取第2步中的指數+2,然后計算階碼: +2 + 127 == 128,128(大于127,說明是一個正數)的二進制數為: 10000000,共8位(階碼是一個正數,可省略符號位)
4.獲取尾數,將第2步中的1.1001000011111101101001101000100-1=1001000011111101101001101000100
5.將第4步的獲取的結果舍掉多余的部分,僅保留高23位: 10010010000111111011010
6.將第3,5步的結果拼接到一塊,并加上符號位(正號0): (符號)0 (階碼)10000001 (尾數)10010010000111111011010
浮點數3.1415926在內存中存儲的二進制數為: 0 10000000 10010010000111111011010
通過上面的例子,說明一下浮點數如何在內存中存儲
C/C++編譯器標準都遵照IEEE制定的浮點數表示法來進行float/double運算,將浮點數轉換為二進制的科學計數法: V = (-1)s * M * 2^E
(-1)s 表示符號位,當s=0,V為正數;當s=1,V為負數.
M表示有效數字,1<=M<2.
E表示指數位
float和double類型,s,M,E的位數為:
符號位s 階碼M 尾數M 長度
float(32bits) 1 8 23
double(64bits) 1 11 52
尾數M的的規則
1.必須保證1≤M<2,也就是說,M可以寫成1.xxxxxx的形式,其中xxxxxx表示小數部分.在計算機內部保存M時,默認這個數的第一位總是1,因此可以被舍去,只保存后面的xxxxxx部分
等到讀取的時候,再把第一位的1加上去.這樣做的好處是節省1位有效數字.以32位浮點數為例,留給 M只有23位,將第一位的1舍去以后,等于可以保存24位有效數字.
2.尾數必須用原碼表示,無論浮點數是正數還是負數.
注:
1985年IEEE(Institute of Electrical and Electronics Engineers)提出了IEEE754標準.該標準規定基數為2,階碼E用移碼表示,尾數M用原碼表示,根據二進制的規格化方法,最高數字位總是1,該標準將這個1缺省存儲,使得尾數表示范圍比實際存儲的多一位.
階碼的規則
階碼的本質上是無符號整數(float 8位;double 11位),但它仍然可以表示負數,其規則為:
對于float來說,階碼=E-127.
對于double來說,階碼=E-1023.
這樣,如果E為正數,則階碼>127; 如果E為負數,則階碼<127. 然后,指數E還可以再分成三種情況:
(1)E不全為0或不全為1.這時,浮點數就采用上面的規則表示,即指數E的計算值減去127(或1023),得到真實 值,再將有效數字M前加上第一位的1.
(2)E全為0.這時,浮點數的指數E等于1-127(或者1-1023),有效數字M不再加上第一位的1,而是還原為 0.xxxxxx的小數.這樣做是為了表示±0,以及接近于0的很小的數字.
(3)E全為1.這時,如果有效數字M全為0,表示±無窮大(正負取決于符號位s);如果有效數字M不全為0,表示 這個數不是一個數(NaN).
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。