浮點(diǎn)數(shù)為什么不精確纷跛?

最近在項(xiàng)目中遇到了浮點(diǎn)數(shù)相加結(jié)果顯示異常的問題妖异,如下圖所示


demo測試結(jié)果

理論上來說惋戏,d應(yīng)該是等于0的,為什么結(jié)果和預(yù)期的不一樣呢他膳,所以抽空研究了一下float

原理

浮點(diǎn)數(shù)的表示有一個 IEEE 的標(biāo)準(zhǔn)响逢,它定義了兩個基本的格式。

  • 用 32 比特表示單精度的浮點(diǎn)數(shù)棕孙,即 float 或者 float32 類型舔亭。
  • 用 64 比特表示雙精度的浮點(diǎn)數(shù),即 double 或者 float64 類型蟀俊。
    這兩種原理差不多钦铺,所以只要看單精度類型的就可以了
浮點(diǎn)數(shù)的標(biāo)準(zhǔn)定義

第一部分是一個符號位,用來表示是正數(shù)還是負(fù)數(shù)肢预,用 s 來表示矛洞,所有的浮點(diǎn)數(shù)都是有符號的。

接下來是一個 8 個比特組成的指數(shù)位烫映。一般用 e 來表示沼本。8 個比特能夠表示的整數(shù)空間噩峦,就是 0~255。我們在這里用 1~254 映射到 -126~127 這 254 個有正有負(fù)的數(shù)上抽兆。浮點(diǎn)數(shù)希望能夠表示很小的數(shù)壕探,所以指數(shù)位也會有負(fù)數(shù)。

最后郊丛,是一個 23 個比特組成的有效數(shù)位。我們用 f 來表示瞧筛。綜合科學(xué)計(jì)數(shù)法厉熟,我們的浮點(diǎn)數(shù)就可以表示成下面這樣: (?1)s × 1.f × 2e

以 0.5 為例子。0.5 的符號為 s 應(yīng)該是 0较幌,f 應(yīng)該是 0揍瑟,而 e 應(yīng)該是 -1,也就是0.5 = (?1)0 × 1.0 × 2?1 = 0.5乍炉,對應(yīng)的浮點(diǎn)數(shù)表示绢片,就是 32 個比特。如下圖所示
0.5

s=0岛琼,e=2?1底循,需要注意,e 表示從 -126 到 127 個槐瑞,-1 是其中的第 126 個數(shù)熙涤,這里的 e 如果用整數(shù)表示,就是 26 + 25 + 24 + 23 + 22 + 21 = 126困檩,1.f=1.0祠挫。

為什么會不精確

10進(jìn)制小數(shù)轉(zhuǎn)換為2進(jìn)制的方法:乘2,然后取整(整數(shù)部分最大為1悼沿,最小為0)等舔,小數(shù)部分繼續(xù)乘2,取整糟趾,直到小數(shù)部分0為止慌植。
以0.1為例,轉(zhuǎn)化如下

乘2 整數(shù)部分 二進(jìn)制表示
1 0.1*2=0.2 0 0
2 0.2*2=0.4 0 0
3 0.4*2=0.8 0 0
4 0.8*2=1.6 1 1
5 0.6*2=1.2 1 1
6 0.2*2=0.4 0 0

從第6行開始就會重復(fù)2~5行的運(yùn)算拉讯,0.1就會變成一個無限循環(huán)的小數(shù):0.000110011……涤浇,這里的0011無限循環(huán)。浮點(diǎn)數(shù)其實(shí)是用二進(jìn)制的科學(xué)計(jì)數(shù)法來表示的魔慷,所以我們可以把小數(shù)點(diǎn)左移三位只锭,這個數(shù)就變成了:1.10011001100110011…× 2-4

這種科學(xué)計(jì)數(shù)法對應(yīng)打上面的格式為:符號位 s = 0院尔,對應(yīng)的有效位 f=1001100110011…蜻展。因?yàn)?f 最長只有 23 位喉誊,那這里“0011”無限循環(huán),最多到 23 位就截止了纵顾。于是伍茄,f=10011001100110011001100。對應(yīng)的指數(shù)為 e施逾,代表的應(yīng)該是 -4敷矫。其對應(yīng)的是123,轉(zhuǎn)化成二進(jìn)制就是 01111011汉额。那么最終的二進(jìn)制表示為:001111011 10011001100110011001100

現(xiàn)在再將二進(jìn)制浮點(diǎn)數(shù)轉(zhuǎn)化為十進(jìn)制曹仗,結(jié)果為0.0999999940395

知道這些有什么用?

在討論這個之前蠕搜,先看一下浮點(diǎn)數(shù)如何相加怎茫。首先要把兩個的指數(shù)位對齊,也就是把指數(shù)位都統(tǒng)一成兩個其中較大的那個妓灌,那么指數(shù)位較小的數(shù)轨蛤,需要進(jìn)行有效位右移,在右移的過程中虫埂,最右側(cè)的有效位就被丟棄掉了祥山。這會導(dǎo)致對應(yīng)的指數(shù)位較小的數(shù),在加法發(fā)生之前掉伏,就丟失精度枪蘑。如果兩個數(shù)的指數(shù)位差出 23 位,較小的數(shù)右移 24 位之后岖免,所有的有效位就都丟失了岳颇。這也就意味著,雖然浮點(diǎn)數(shù)可以表示上到 3.40×1038颅湘,下到 1.17×10?38 這樣的數(shù)值范圍话侧。但是在實(shí)際計(jì)算的時(shí)候,只要兩個數(shù)闯参,差出 224瞻鹏,也就是 16777216倍,那這兩個數(shù)相加之后鹿寨,結(jié)果完全不會變化新博。如下圖所示

浮點(diǎn)數(shù)相加

這就是浮點(diǎn)數(shù)運(yùn)算大數(shù)吃小數(shù)的問題,那么怎么解決呢脚草,方法其實(shí)也很簡單赫悄,就是記錄一下誤差用于下次計(jì)算
gap

舉個例子,比如我們需要循環(huán)計(jì)算2000w個1.0,根據(jù)上面的可知埂淮,當(dāng)計(jì)算到16777216就會出現(xiàn)大數(shù)吃小數(shù)的情況姑隅,那么就會造成嚴(yán)重的誤差
2000w個1.0相加

如果我們記住每次的誤差,就能解決這個問題

參考文章:深入淺出計(jì)算機(jī)組成原理

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末倔撞,一起剝皮案震驚了整個濱河市讲仰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌痪蝇,老刑警劉巖鄙陡,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異躏啰,居然都是意外死亡柔吼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門丙唧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人觅玻,你說我怎么就攤上這事想际。” “怎么了溪厘?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵胡本,是天一觀的道長。 經(jīng)常有香客問我畸悬,道長侧甫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任蹋宦,我火速辦了婚禮披粟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘冷冗。我一直安慰自己守屉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布蒿辙。 她就那樣靜靜地躺著拇泛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪思灌。 梳的紋絲不亂的頭發(fā)上俺叭,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機(jī)與錄音泰偿,去河邊找鬼熄守。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的柠横。 我是一名探鬼主播窃款,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼牍氛!你這毒婦竟也來了晨继?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤搬俊,失蹤者是張志新(化名)和其女友劉穎紊扬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唉擂,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡餐屎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了玩祟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腹缩。...
    茶點(diǎn)故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖空扎,靈堂內(nèi)的尸體忽然破棺而出藏鹊,到底是詐尸還是另有隱情,我是刑警寧澤转锈,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布盘寡,位于F島的核電站,受9級特大地震影響撮慨,放射性物質(zhì)發(fā)生泄漏竿痰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一砌溺、第九天 我趴在偏房一處隱蔽的房頂上張望影涉。 院中可真熱鬧,春花似錦规伐、人聲如沸常潮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喊式。三九已至,卻和暖如春萧朝,著一層夾襖步出監(jiān)牢的瞬間岔留,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工检柬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留献联,地道東北人竖配。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像里逆,于是被迫代替她去往敵國和親进胯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容