前言
了解IEEE-754之前,先了解下什么是十進制和二進制,以及它們之間如何轉化
十進制
十進制按照字面意思來理解,就是逢十進一,比如我們現在用的貨幣也好,計算也好,都是十進制,用0-9十個數字來表示
二進制
十進制十逢十進一,二進制就是二進一,用0和1來表示所有的數字
二進制轉十進制
二進制轉十進制,基本上是按位乘以2的n次方,再累加得到結果
比如二進制數1110.0101,轉化為十進制
十進制轉二進制
十進制轉二進制,整數部分需要除以2,取余數,繼續對結果除以2,直到余數為0;小數部分需要乘以2,取整數部分,繼續對結果的小數部分乘以2,直到結果的小數部分為0
比如十進制數:13.125,轉為二進制數的計算過程
整數部分是13,得到的二進制結果是
小數部分是0.125,得到的二進制結果是
什么是IEEE
IEEE二進制浮點數算術標准(IEEE 754)是20世紀80年代以來最廣泛使用的浮點數運算標准,為許多CPU與浮點運算器所采用。這個標准定義了表示浮點數的格式(包括負零-0)與反常值(denormal number)),一些特殊數值(無窮(Inf)與非數值(NaN)),以及這些數值的“浮點數運算符”;它也指明了四種數值舍入規則和五種例外狀況(包括例外發生的時機與處理方式)。
IEEE 754規定了四種表示浮點數值的方式:單精確度(32位)、雙精確度(64位)、延伸單精確度(43比特以上,很少使用)與延伸雙精確度(79比特以上,通常以80位實現)。只有32位模式有強制要求,其他都是選擇性的。大部分編程語言都有提供IEEE浮點數格式與算術,但有些將其列為非必需的。例如,IEEE 754問世之前就有的C語言,有包括IEEE算術,但不算作強制要求(C語言的float通常是指IEEE單精確度,而double是指雙精確度)。
IEEE浮點計算缺點
從上面的說明我們可以清楚的知道,IEEE就是基於二進制的浮點運算,我們日常使用的四則運算,也就是加減乘除,如果是使用IEEE標准進行處理的話,有可能會出現精度問題,比如十進制數0.1用二進制表示
從上面的計算結果可以看出,死循環了。。。也就是說十進制0.1是無法使用二進制准確表示的
打開任何一個網站,F12進入開發者模式,在console中輸入0.1+0.2,你會發現,結果的精度也有問題
既然會出現精度問題,但是為什么我們平時開發的過程中沒有出現重大問題呢?
其實都是被忽悠的,由於我們平時的計算,四舍五入基本上就能得出我們想要的結果,編程語言在處理四則運算的時候其實會對一些無法准確表示的結果進行四舍五入等處理,造成一定的錯覺
解決方案
大部分編程語言都使用浮點數進行運算,處理四則運算會造成精度問題,如果你需要高精度計算,那你必須使用其他方案
PHP:如果你的編程語言是PHP的話,而你又需要高精度運算,那你可以選擇使用PHP的 bcMath 進行高精度運算
Java:如果你的編程語言是Java的話,高精度計算可以使用 BigDecimal 進行處理
總結
普通的四則運算,精度只是偶然的,誤差時常發生,在處理金額等敏感問題時,盡量選擇高精度的運算進行處理,避免出現不必要的麻煩
參考:IEEE-754