1. 首先看問題結果
是不是結果還是 30000000.0f 而不是 30000003.0f
2. 分析原因
這是一個典型的大數喫小數問題,原因需要從浮點數的計算機實現說起
對於float,是4字節(強調下我這裏講的都是32位浮點數,其它位思想同樣適用),共32個bit,那麼怎麼用這32位來表示float
首先最容易想到的是 浮點數的每位十進制數用4bit來表示,比如 999999.99 這樣每個9用1001表示,那麼在32bit上的佈局是下面這樣: 100110011001100110011001.10011001 這樣的表示數據範圍是 000000.00 ~ 999999.99 共大概1億個數字,這種把小數點固定的方法就是 “定點小數”,這樣表達簡單易懂,但是有個缺點就是,明明32bit可以最多表示42億個數字,現在只能表示1億,太浪費了。
還有一個就是 “浮點小數” ,顧名思義,就是小數點會浮動,比如 99.5 你可以表示成 9.995 x 10^1,也可以
表示成0.9995 x 10^2, 小數點可以浮動必然需要引入指數,這就是我們學數學的時候說的科學計數法,但是這是10進制,二進制數同樣適用,只是科學計數法的底數是2而已。對於浮點數的二進制表示 常規的是 IEEE-754標準(強調下我下面講都是IEEE-754標準),回頭我打算再寫一篇博客專門介紹一下這個標準(可以到時候留意下我的博客更新),現在我們只需要知道,這套標準定義下的浮點數是把32位bit位,劃分爲3部分:
對於 30000000.0f,二進制浮點數表示如下:
A = 0 10010111 11001001110000111000000 (依次是符號位1位 指數位8位 數字位23位)
對於 3.0f,二進制浮點數表示如下:
B = 0 10000000 10000000000000000000000 (依次是符號位1位 指數位8位 數字位23位)
轉換工具可參考 : https://www.h-schmidt.net/FloatConverter/IEEE754.html
現在就是 A + B ,其中A和B的指數位和數字位均不同,CPU此時會把 A和B的指數位統一(向大數A的指數靠攏),這樣只要 加 A和B的數字位就可以了,A和B的指數位相差23位,如果B的指數位要跟A一致,那麼B的數字位就要整體向右移動23位,正好把B的數字部分
10000000000000000000000 第一個1溢出了,這就是爲什麼 30000000.0f + 3.0f 結果還是 30000000.0f的原因。
特別提醒下,IEEE754 的指數位表示的不是真實的指數值,而是有個映射關係:1~254(bit表示值,0和255有另外的作用) 映射到 -126~127(指數表示的真實值) 這 254 個有正有負的數上。如果我們把 32bit劃分的3個部分分別表示爲 s(符號位),e(指數位),f(數字位),那麼沒有參與映射的0和255有如下的作用:
下篇我在講IEEE754標準的博客裏會把這個也交代清楚