北郵CSAPP第二章之浮點數

櫻滿無門發表於2020-12-17

浮點數

  • 浮點數:範圍大而不精確
  • 本節內容:如何表示浮點數,浮點數的舍入,浮點數的運算

二進位制小數

  • 小數的二進位制表示法只能表示哪些能構被寫成x × 2^y的數,其它值只能近似地表示
  • 增加二進位制表示的長度即可提高表示的精度

IEEE浮點表示

  • V = (-1)^s · M · 2^E

  • s:sign

  • M:尾數

  • E:階碼,對浮點數加權

  • 將浮點數的位表示劃分為三個段
    s | exp | frac
    exp: k位的階碼欄位
    frac: n位小數字段

  • float:s:1位,exp:8位,frac:23位

  • double:s:1位,exp:11位,frac:52位

(由階碼的值決定)

  • exp != 0 && exp != 255:規格化

  • exp == 0:非規格化

  • exp == 255 and frac == 0:無窮大

  • exp == 255 and frac != 0:NaN

  • 規格化
    階碼欄位被解釋為一個以偏置值表示的有符號整數。值:E = e - Bias,E為無符號數,Bias = 2^(k - 1) - 1
    單精度:-126 ~ 127
    雙精度:-1022~1023
    M = 1 + f(隱含的以1開頭的表示)

  • 非規格化
    E = 1 - Bias(使得其能進行平滑的變化)
    M = f(不包含隱藏的1)

  1. 提供了一個表示0的方法
  2. 表示非常接近0的數字
  • 值 +0.0總有一個全為0的位表示

  • 最小的正非規格化位表示:最低有效位為1,其它所有位為0,V = 2^(-n - 2^(k - 1) + 2)

  • 最大的非規格化值是階碼全為0且小數字段全為1,V = (1 - 2(-n))·2(-2^(k - 1) + 2)

  • 最小的正規格化值:階碼欄位的最低有效位為1,其它位全為0。V = 2 ^ (-2^(k - 1) + 2)

  • 最大的正規格化值:位表示符號位為0,階碼的最低有效位為0,其它全為1,V = (1 - 2^(-n-1)) · 2(2(k - 1))

  • 一些東西

  1. 1 − B i a s 1-Bias 1Bias使得變化更加平滑
  2. float: B i a s = 2 k − 1 − 1 = 127 Bias=2^{k-1}-1=127 Bias=2k11=127
  3. 越靠近原點越稠密(浮點數能表示的數)
  4. 將浮點數能表示的最小的數一直到無限大進行排列,發現若按照無符號整數進行解釋,依然是升序
  5. 12345=>12345.0的轉換:12345=[11000000111001],共14位,若用浮點數表示,在M位為 1.100000011100 1 2 1.1000000111001_2 1.10000001110012,忽略1,需要移動13位。又因為 E = e − B i a s E=e-Bias E=eBias,有 e = 13 + 127 = 140 = [ 10001100 ] e=13+127=140=[10001100] e=13+127=140=[10001100]。加上符號位0,再將M尾部用0補足,得[01000110010000001110010000000000]
  6. 一個具有n位小數的有效位數為(n+1)位(隱藏的1),因此不能準確描述的最小正整數的值為 2 n + 1 + 1 2^{n+1}+1 2n+1+1

舍入

表示方法限制了浮點數的範圍與精度,因此浮點運算只能近似表示實數運算
使用舍入運算來找到最接近的匹配值

  • 關鍵問題:在兩個可能值的中間確定舍入方向
    IEEE定義了四種不同的舍入方式。預設尋找最近的匹配值。其它三種用於計算上下界

  • 向偶數舍入(向最近的匹配值舍入):預設方式。將數字向上或向下舍入,使得結果的最低有效數字是偶數。這種方法將1.5與2.5均舍入為2

  • 其它三種方式:向零舍入、向下舍入、向上舍入

  • 向零舍入將負數向上舍入、正數向下舍入

  • 為什麼偏偏要將向偶數舍入作為目標?
    若全部向上或向下舍入,最終得到的算術平均值將偏高或偏低
    向偶數舍入在大多數情況下避免了這種誤差

  • 在不想舍入到整數的時候,也可以舍入到偶數。考慮最低有效位為奇數還是偶數。

  • 向偶數舍入法能運用在二進位制小數上
    將最低有效位的值0認為是偶數,1認為是奇數
    若為可能的中間值(即距離頂部與底部的長度相等),則傾向於使最低有效位為0
    若不為可能的中間值,則舍入到最近的區域
    只有當二進位制小數的最後一位有效數字為1時才有效(即有小數部分)

浮點運算

浮點運算:定義某個運算 x ? f y = R o u n d ( x ? y ) x ? ^fy=Round(x ? y) x?fy=Round(x?y)
對實際運算的精確結果進行舍入後的結果
實際使用一些小技巧來避免執行精確的計算,計算只要精確到能保證得到正確的舍入結果即可
當引數中有特殊值時,將通過一些特殊的規則進行計算

  • 指定浮點運算優勢之一:可以獨立於任何具體的硬體或者軟體實現

浮點加法

可交換、單調性、不可結合

  • 實數的加法也構成了阿貝爾群,但是舍入會對其造成影響

  • 大多數值在浮點加法下有逆元: x + f − x = 0 x+^f-x=0 x+fx=0(無窮與NaN是例外,因為 N a N + f x = N a N NaN+^fx=NaN NaN+fx=NaN),也是可交換的: x + f y = y + f x x+^fy=y+^fx x+fy=y+fx

  • 由於舍入,實數的加法是不可結合
    例如:(單精度下)
    (3.14+1e10)-1e10=0=>3.14由於舍入將丟失
    3.14+(1e10-le10)=3.14

  • 由於浮點加法不具有結合性,將在程式編寫底層產生影響
    a + b + c ! = a + ( b + c ) a + b + c != a + (b + c) a+b+c!=a+(b+c)

  • 另一方面,浮點加法滿足了單調性屬性 a > = b , 則 x + a > = x + b ( x ! = N a N ) a>=b ,則x+a>=x+b(x != NaN) a>=b,x+a>=x+b(x!=NaN)
    疑惑:無符號或補碼加法不具有單調性屬性?

浮點乘法

浮點乘法:定義 x ⋅ f y = R o u n d ( x ⋅ y ) x · ^fy=Round(x·y) xfy=Round(xy),該計算是可交換的,乘法單位元(這是什麼?)為1.0

  • 因為會發生溢位舍入丟失資訊,不具有可結合性
    例如:(單精度)
    ( 1 e 20 ∗ 1 e 20 ) ∗ 1 e − 20 = + ∞ (1e20*1e20)*1e-20=+∞ (1e201e20)1e20=+(溢位)
    1 e 20 ∗ ( l e 20 ∗ l e − 20 ) = l e 20 1e20*(le20*le-20)=le20 1e20(le20le20)=le20

  • 另外,浮點乘法不具有加法分配性
    l e 20 ∗ l e 20 − l e 20 ∗ l e 20 = N a N le20*le20-le20*le20=NaN le20le20le20le20=NaN(溢位)
    l e 20 ∗ ( l e 20 − l e 20 ) = 0.0 le20*(le20-le20)=0.0 le20(le20le20)=0.0

  • 當均不為NaN時滿足單調性
    a > = b 且 c > = 0 = > a ∗ f c > = b ∗ f c a > = b 且 c < = 0 = > a ∗ f c < = b ∗ f c a >= b 且 c>=0 => a * ^fc >= b * ^fc a >= b 且 c<=0 => a * ^fc <= b * ^fc a>=bc>=0=>afc>=bfca>=bc<=0=>afc<=bfc
    疑惑:無符號乘法或補碼乘法不具有單調性?
    解答: x ∗ y x*y xy可能溢位,兩個正數相乘可能得到負數,加法也是這樣,因此不具有單調性

  • 缺乏結合性與分配性是很嚴重的問題

C語言中的浮點數

  • C語言提供float與double

  • 在支援IEEE的機器上,向偶數舍入

  • 因為C語言不要求機器使用IEEE,因此沒有辦法得到-0、NaN等特殊值

  • 若出現下面句子時

#define _GUN_SOURCE 1
#include <math.h>

將使用程式常數INFINITYNAN

相關文章