Just My Life & My Work

很多程式設計師都會有浮點數精準度 (Floating-Point Precision)的問題,但常常只知道double的精準度大於float,卻不知道double精準度多少,也不知道float精準度多少,反正就用精準度最大的double就好。但其實原理很簡單,計算機概論中就有提到IEEE 754對浮點數的規範,只要稍微瞭解一下其定義即可。

C&C++程式語言的浮點數表示法有兩種,單倍精確度的float雙倍精確度的double,這兩種浮點數規格是來自IEEE 754

其中雙倍精確度會比單倍精確度來的精準,那到底是為什麼呢?很多人有這個問題,就連程式設計師遇到運算結果與理想的數值不對,也常常不知其所以然,剛好又有人問我這個問題,我還是把它給分析出來,讓更多人明白浮點數精準度 (Floating-Point Precision)吧!

IEEE 754則是把浮點數分成三個部份(如圖):

Sign / Exponent / Fraction
1. Sign bits: 用來表示該浮點數是正or負
(float: 1 bit / double: 1 bit)
2. Exponent: 用來表示該浮點數正規化後的"次方數"
(float: 8 bits / double: 11 bits)
何謂正規化:讓所有的實數表示成1.xxxx*10的n次方
例如:777.0正規化後會變成7.77*10的2次方
3. Fraction: 用來儲存小數位數
(float: 23 bits / double: 52 bits)

以上的解釋可能有點複雜,那我們來看表格吧~

32位單精度

單精度二進制小數,使用32個位元存儲。
S 為符號位,Exp為指數位,Fraction為有效數位。

64位雙精度

雙精度二進制小數,使用64個位元存儲。
S 為符號位,Exp為指數位,Fraction為有效數位。

這時候就有人想到精準度就直接看Fraction就好啦!因為它就說是精準度了嘛~哈!沒錯,但是要記住float: 23 bits / double: 52 bits代表二進制,這對已經熟悉十進制的我們不太好理解,所以把它轉成十進制吧~

很多人都會直接把float: 23 bits / double: 52 bits當成十進制,這裡一定要特別注意哪~還有數的範圍有效數字並沒有直接關係,這是許多人常犯的錯誤喔!很多人常以為數的範圍都那麼大了,所以精準度也就會很大,這是錯誤的概念。

以下是32位元64位元有效數字2進位10進位的過程。

學弟用下列的程式碼問我,為什麼出來的結果c會跑出 0.29999998 或 0.30000001 這些不確定且不精確的結果。

int a=3; float b=10; float c; c=a/b;

改用double之後問題就解決了,哈~其實沒有,再去想想為什麼吧!其實之前有寫精準度 (Precision)型態的精準度和大小(Precision and Size of Type),連過去看看,就會更瞭解精準度的問題!

那麼還是有人會問,難道精準度沒有百分之百精準?答案是有的,但你得跳脫IEEE 754的規範,自己建立資料結構大數,如此一來無論多大的天文數字,一樣可以非常精準,但你卻得花更多的空間儲存就是了~

之所以有IEEE 754規範,是因為硬體設計決定了我們要有所取捨,你想要數值範圍,那就得犧牲精準度,反之亦然,因此IEEE 754才會去定義怎樣的數值範圍精準度會恰到好處。

參考:WiKi – 浮點數、WiKi – 單精確浮點數、WiKi – 雙精度浮點數、WiKi – IEEE 754float跟double小知識

Comments on: "[C&C++] 浮點數精準度 (Floating-Point Precision)" (1)

  1. […] Lab轉到RGB色彩空間顯示結果,使用PhotoImapct色彩標定為RGB(0, 255, 1),我並沒有打錯,色彩空間轉回去不再是原圖……原因是轉換過程在程式中是以浮點數做運算,我們知道浮點數精準度有某程度的誤差,所以才會導致前後不符的結果。 […]

隨意留個言吧:)~

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料

標籤雲