浮點精度問題是怎么產(chǎn)生的?

浮點精度問題是怎么產(chǎn)生的

對于小數(shù)的運算,相信大家都有遇到過精度丟失問題,利于0.1+0.2得到的是0.30000000000000004而不是0.3,那么如何解釋為什么計算機中 0.2 + 0.1 不等于 0.3 呢?在剖析這個問題之前我們要先理解IEEE754標準。

什么是IEEE754?下面是一段官方的解釋了解即可,重點是我們要關(guān)注IEEE754存儲格式。

概念:IEEE二進制浮點數(shù)算術(shù)標準(IEEE754)是20世紀80年代以來最廣泛使用的浮點數(shù)運算標準,為許多CPU與浮點運算器所采用。這個標準定義了表示浮點數(shù)的格式(包括負零-0)與反常值(denormal number),一些特殊數(shù)值(無窮∞與非數(shù)值NaN),以及這些數(shù)值的“浮點數(shù)運算符”。 常見的四種浮點數(shù)值表示方式:單精確度(32位)、雙精確度(64位)、延伸單精確度(43比特以上,很少使用)與延伸雙精確度(79比特以上,通常以80位實現(xiàn))。C語言的float通常是指IEEE單精確度,而double是指雙精確度。

存儲格式:IEEE 754標準準確地定義了單精度和雙精度浮點格式

單精度浮點格式(32 位)。

雙精度浮點格式(64 位)。

EEE754 標準中規(guī)定 float 單精度浮點數(shù)在機器中表示用 1 位表示數(shù)字的符號,用 8 位表示指數(shù),用 23 位表示尾數(shù),即小數(shù)部分。對于 double 雙精度浮點數(shù),用 1 位表示符號,用 11 位表示指數(shù),52 位表示尾數(shù),其中指數(shù)域稱為階碼。IEEE754 浮點數(shù)的格式如下圖所示。

下面以0.1和0.2為例將其轉(zhuǎn)換為IEEE754的格式存儲到內(nèi)存中

0.1這個浮點數(shù)轉(zhuǎn)換成一個二進制數(shù)0.00011001100110011...

0.2這個浮點數(shù)轉(zhuǎn)換成一個二進制數(shù)0.0011001100110011...

這兩個浮點數(shù)無法精確轉(zhuǎn)換成一個二進制數(shù),由于在內(nèi)存中表示精度有限必須舍棄后面的尾數(shù)部分。

單精度為例0.1和0.2轉(zhuǎn)換為IEEE754格式以如下

0.1 : 0 01111011 10011001100110011001100

0.2:? 0 01111100 10011001100110011001100

所以我們看到0.1+0.2得到的是0.300000004而不是0.3的結(jié)論,而造成這個精度問題的根本原因在于不是所有的數(shù)字(如例子中的0.1和0.2)都可以用二進制表示而進行截斷,造成精度丟失。

但是盡管如此我們還是有辦法在運算是避免精度問題,那就是BigDecimal,那么BigDecimal是怎么解決這個問題的呢?

解決方案就是不使用用二進制,而是使用十進制(BigInteger)+小數(shù)點位置(scale)來表示小數(shù),所有的十進制數(shù)字都可以用這種形式來表示,比如 0.1? =1*10^-1? ? ? scale=1

BigDecimal 運算分成兩部分? ,BigInteger部分和更新scale即可,具體有興趣的同學可以翻翻BigDecimal 的源碼,在這里不再展開了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容