浮點數的計算機不計算機表計算機表示(IEEE 754),由 UCB 數學教授 William Kahan 主要起草。想過小數后者也因其卓越貢獻于1989年獲得圖靈獎。計算機不計算機表計算機組成原理與匯編語言這兩門課均對該內容有所講解。想過小數與課程中直接拋出公式與概念不同,計算機不計算機表我想首先與各位探討"科學計數法"這個概念,進而討論設計二進制的科學計數法需要涉及到哪些元素。接著,我們討論如何在內存上表達這個方案。最后討論計算機的具體實現。
科學計數法
我們都了解科學計數法。科學計數法的精妙之處在于,其將"量級"與"數值"兩個信息拆分,讓使用者對這兩個信息更加明確。
如上,我們可以將任何有理數拆分成 的形式。值得注意的是:
的取值范圍是 一定是一個整數
對于任何有理數,我們都可以用兩個范圍狹小(規則明確)的數字 B 與 C 來表示。
此外,我們知道,十進制只不過是記錄數字大小的一種方式而已。歷史上出現過的二進制、三進制、二十進制,都可以毫無障礙地表示數字,并且還有其獨具的數學特性。
那么,二進制可以用科學計數法表示嗎?答案當然是肯定的。
二進制的科學計數法
注意,這里下標2,代表這個數是二進制。同理, 對應十進制中的數字 。
通過觀察十進制的科學計數法形式,對于二進制,我們自然可以做出如下約定:
的取值范圍是 一定是一個整數
這里我們補充說明一下,二進制的小數是什么樣的。對于 這個十進制數,如果要將其轉換為二進制:
將其整數部分與小樹部分分開; 對于整數部分 5
,我們使用"不斷除以2取余數"的方法,得到101
;對于小數部分 .25
,我們使用"不斷乘以2取整數"的方法,得到.01
。
關于進制轉換的具體方法與背后的數學原理,我寫過一篇文章進行討論,見這里:十進制轉二進制 / 八進制 / 十六進制的手算方法,及其數學原理的通俗解釋。
這里,我們只需要明確,二進制是存在小數形式的,且可以表示一切十進制可表示的數(的近似)。
計算機如何記錄二進制的科學計數法
接著,我們步入正題:只會表示0/1的計算機,如何記錄并表達浮點數呢?
給一個32位的空間,如果不做任何約束,我們只能將其理解為一個整數,并且其取值范圍為 。
這是因為,計算機只能記錄 0 和 1 這兩個信息,并不能直接記錄小數點點在哪里。因此,我們需要設置一定規則,取出一定位,用于表示小數點點在哪里。這必將犧牲一定的精度與取值范圍。
因此,我們將這 32 位空間分為三部分:
第一部分,用于表示 精度
,即這個數字值是多少,對應上面的B;第二部分,用于表示 小數點
,即量級,對應上面的C;第三部分,用于表示 正負
,只需要使用1位。
在 IEEE 754 中,我們分別將上述一、二、三部分叫做尾數M
,階碼E
,符號s
。于是我們有了二進制的表達式:
為了表示盡可能多的、常用的小數,我們有如下需求:
對于符號位 s ,如果該位上是 0 ,則為正數;為 1 ,則為負數。 對于尾數 M ,其取值范圍為 ; 對于階碼 E ,其為一個整數,并且取值范圍應該包含負數、0、正數。
可以注意到,對于 M 、 E ,我們并不能直接用二進制表示,還需要設定一定規則。
尾數 M
假設尾數 M 一共有 f 位,則 f 可表示的整數取值范圍為 ,我們稱 f 直接對應的非負整數為 C 。為了將其投影到 ,我們做出如下變換:
解碼 E
假設解碼 E 一共有 e 位,則 e 可表示的整數取值范圍為 ,我們稱 e 直接對應的非負整數為 Exp 。我們希望 E 可以取到負數,因此做出如下變換:
這樣,我們的 E 取值范圍就來到了 。
總結
有了如上設計的規則,我們便知曉了計算機記錄浮點數的方式,以及轉換流程。以下圖為例。
知識點與例題
上面我們討論了 IEEE 754 的思想,但是并不嚴謹,比如:
正負無窮該怎么表達? 如此表示會不會造成空間的浪費? ...
因此,我們從數學上嚴謹地討論一道例題,考慮一下規格化浮點數。例題源自我的匯編語言筆記。
題目
給定一個浮點格式(IEEE 754),有k位指數和n位小數,對于下列數,寫出階碼E、尾數M、小數f和值V的公式。另外,請描述其位表示。
數5.0; 能夠被準確描述的最大奇數; 最小的正規格化數。
解決
前置知識一:IEEE 754
IEEE 754約定,計算機中浮點數二進制表示為:
數字形式:
符號:s 尾數:M,是一個位于區間[1.0, 2.0)內的小數 階碼:E
編碼形式:
s | exp | frac |
---|
exp域:E(注意,E要進行變換,再存儲在exp中); frac域:M。
前置知識二:規格化浮點數(Normalized)
這里討論到規格化浮點數(Normalized):
滿足條件:exp不全為0且不全為1。 真實的階碼值需要減去一個偏置(biased)量: 單精度數:127(Exp:1...254,E:-126...127) 雙精度數:1023(Exp:1...2046,E:-1022...1023) ,e = exp的域的位數 E = Exp - Bias Exp:exp域所表示的無符號數值 Bias的取值: frac的第一位隱含1:M = 1.xxx...x_2 因此第一位的“1”可以省去,xxx...x:bits of frac Minimum when 000...0 ( ) Maximum when 111...1 ( )
前置工作一:整理變量關系
則E為
E最大值為 。(為什么不是 呢?因為有規定:exp全部取1為“非規格化浮點數”,因此規格化浮點數中exp不能全部取1,頂多為(1)*(0)
)
E的最小值為 。(為什么不是 呢?因為有規定:exp全部取0為“非規格化浮點數”,因此規格化浮點數中exp不能全部取0,頂多為(0)*(1)
)
前置工作二:總結特性
拋開例題,來看一個例子:
8位浮點數表示:exp域寬度為4 bits,frac域寬度為3 bits。則,其偏置量的值為2^(4-1) - 1 = 7. 其他規則符合IEEE 754規范。
取值范圍如下表。
s | exp | frac | E | value |
---|---|---|---|---|
0 | 0000 | 000 | -6 | 0 |
0 | 0000 | 001 | -6 | 1/8 * 1/64 = 1/512 |
0 | 0000 | 010 | -6 | 2/8 * 1/64 = 2/512 |
... | ||||
0 | 0000 | 110 | -6 | 6/8 * 1/64 = 6/512 |
0 | 0000 | 111 | -6 | 7/8 * 1/64 = 7/512 |
0 | 0001 | 000 | -6 | 8/8 * 1/64 = 8/512 |
0 | 0001 | 001 | -6 | 9/8 * 1/64 = 9/512 |
... | ||||
0 | 0110 | 110 | -1 | 14/8 * 1/2 = 14/16 |
0 | 0110 | 111 | -1 | 15/8 * 1/2 = 15/16 |
0 | 0111 | 000 | 0 | 8/8 * 1 = 1 |
0 | 0111 | 001 | 0 | 9/8 * 1 = 9/8 |
0 | 0111 | 010 | 0 | 10/8 * 1 = 10/8 |
... | ||||
0 | 1110 | 110 | 7 | 14/8 * 128 = 224 |
0 | 1110 | 111 | 7 | 15/8 * 128 = 240 |
0 | 1111 | 000 | n/a | inf |
可以看出,假設frac有f位,則M可視為:
其中,C是整數,由frac決定,即 ;
并且C滿足 。
則浮點數V的十進制即為:
也可寫作 :
其中, 、 分別為exp、frac位數,為常數。
解決問題一:數0.5
較為簡單,直接解決如下。
0.5???//?轉換為二進制?==>
0.1???//?移動小數點,使其在最左邊的1之后
M??=?1.0?//?小數點后的數字存儲在frac中
E?=?-1?//?因為是左移
frac=?0*?//?共n位
exp?=?E?+?Bias
?=?-1?+?(2^(e-1)?-?1)
則,位的描述為:
s | exp | frac |
---|---|---|
0 | bin(-1 + (2^(e-1) - 1)) | 00....(共n位) |
解決問題二:能夠被準確描述的最大奇數
根據前置工作二,可以看出,對于規格化浮點數可化簡為:
現在的任務有兩個:
是整數,不能有小數(則 應大于等于 ); 是奇數( 不是奇數,因此使 為奇數,則 取1,則取 )。
下面分類討論:
情況一:E可以取到f時,
即 時,
取 , 取其能取的最大奇數,對應的二進制為: exp:dec2bin( ),frac:1*
(frac全為1)
情況二:E取不到f時,
這種情況不可能,因為E取不到f,則很多整數都不能表示。
解決問題三:最小的正規格化數
觀察:
則 取 , 、 分別取最小。
由前置工作一, 取 , 取 ,對應的二進制為: exp:0*1
,frac:0*
后記:我第一學習浮點數是在2019年年末,當時對于浮點數的筆記和理解是有問題的。在此感謝一位湖南大學的朋友(公眾號 / CSDN:梓酥),給我發郵件,指出我的問題~
往期推薦
免責聲明:本文內容由21ic獲得授權后發布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯系我們,謝謝!