JavaScript 浮點數(shù)精度問題小結
一. 引言
浮點數(shù)精度問題是指在計算機中使用二進制表示浮點數(shù)時,由于二進制無法精確表示某些十進制小數(shù),導致計算結果可能存在舍入誤差或不精確的情況。
這個問題主要源于浮點數(shù)的存儲方式。在計算機中,浮點數(shù)通常使用IEEE 754標準來表示。該標準將浮點數(shù)分為符號位、指數(shù)位和尾數(shù)位,使用科學計數(shù)法來表示一個浮點數(shù)。
二. 常見浮點數(shù)精度問題
1. 示例一:浮點值運算結果
// 加法 console.log(0.1 + 0.2); // 0.30000000000000004 console.log(0.7 + 0.1); // 0.7999999999999999 console.log(0.2 + 0.4); // 0.6000000000000001 console.log(2.22 + 0.1); // 2.3200000000000003 // 減法 console.log(1.5 - 1.2); // 0.30000000000000004 console.log(0.3 - 0.2); // 0.09999999999999998 // 乘法 console.log(19.9 * 100); // 1989.9999999999998 console.log(19.9 * 10 * 10); // 1990 console.log(9.7 * 100); // 969.9999999999999 console.log(39.7 * 100); // 3970.0000000000005 // 除法 console.log(0.3 / 0.1); // 2.9999999999999996 console.log(0.69 / 10); // 0.06899999999999999
運行結果如下圖所示:
2. 示例二:小數(shù)乘以10的n次方取整(比如:元轉分,米轉厘米)
console.log(parseInt(0.58 * 100, 10)); // 57
在上面的例子中,我們得出的結果是 57,而不是預期結果 58。
3. 示例三:四舍五入保留 n 位小數(shù)
例如我們會寫出 (number).toFixed(2) ,但是看下面的例子:
console.log((1.335).toFixed(2)); // 1.33
在上面的例子中,我們得出的結果是 1.33,而不是預期結果 1.34。
三. 為什么會出現(xiàn)這樣的結果
1. 浮點數(shù)表示
在計算機中,浮點數(shù)通常使用IEEE 754標準來表示。該標準將浮點數(shù)分為符號位、指數(shù)位和尾數(shù)位,使用科學計數(shù)法來表示一個浮點數(shù)。
該規(guī)范定義了浮點數(shù)的格式,對于 64 位的浮點數(shù)在內(nèi)存中的表示,最高的 1 位是符號位,接著的 11 位是指數(shù),剩下的 52 位為有效數(shù)字,具體表示方式如下:
符號位 S:用于表示正負號。第 1 位是正負數(shù)符號位(sign),0 代表正數(shù),1 代表負數(shù)。
指數(shù)位 E:用于表示浮點數(shù)的指數(shù)部分,以二進制補碼形式存儲。中間的 11 位存儲指數(shù)(exponent),用來表示次方數(shù)。
尾數(shù)位 M:用于表示浮點數(shù)的有效數(shù)字部分,以二進制形式存儲。最后的 52 位是尾數(shù)(mantissa),儲存小數(shù)部分,超出的部分自動進一舍零。
即:浮點數(shù)最終在運算的時候?qū)嶋H上是一個符合該標準的二進制數(shù)
符號位決定了一個數(shù)的正負,指數(shù)部分決定了數(shù)值的大小,小數(shù)部分決定了數(shù)值的精度。
IEEE 754 規(guī)定,有效數(shù)字第一位默認總是 1,不保存在 64 位浮點數(shù)之中。也就是說,有效數(shù)字總是 1.xx…xx 的形式,其中 xx…xx 的部分保存在 64 位浮點數(shù)之中,最長可能為 52 位。因此,JavaScript 提供的有效數(shù)字最長為 53 個二進制位(64 位浮點的后 52 位 + 有效數(shù)字第一位的 1)。
既然限定位數(shù),必然有截斷的可能。
2. 舉例說明
示例一
console.log(0.1 + 0.2); // 0.30000000000000004
為了驗證該例子,我們得先知道怎么將浮點數(shù)轉換為二進制,整數(shù)我們可以用除 2 取余的方式,小數(shù)我們則可以用乘 2 取整的方式。
*0.1* 轉換為二進制
0.1 * 2,值為 0.2,小數(shù)部分 0.2,整數(shù)部分 0
0.2 * 2,值為 0.4,小數(shù)部分 0.4,整數(shù)部分 0
0.4 * 2,值為 0.8,小數(shù)部分 0.8,整數(shù)部分 0
0.8 * 2,值為 1.6,小數(shù)部分 0.6,整數(shù)部分 1
0.6 * 2,值為 1.2,小數(shù)部分 0.2,整數(shù)部分 1
0.2 * 2,值為 0.4,小數(shù)部分 0.4,整數(shù)部分 0
從 0.2 開始循環(huán)
*0.2* 轉換為二進制
可以直接參考上述,肯定最后也是一個循環(huán)的情況
所以最終我們能得到兩個循環(huán)的二進制數(shù):
0.1:0.0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1100 ...
0.2:0.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 ...
這兩個的和的二進制就是:
sum:0.0100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 ...
最終我們只能得到和的近似值(按照 IEEE 754 標準保留 52 位,按 0 舍 1 入來取值),然后轉換為十進制數(shù)變成:
sum ≈ 0.30000000000000004
示例二
console.log((1.335).toFixed(2)); // 1.33
因為 1.335 其實是 1.33499999999999996447286321199,toFixed 雖然是四舍五入,但是是對 1.33499999999999996447286321199 進行四五入,所以得出 1.33。
示例三
在 Javascript 中,整數(shù)精度同樣存在問題,先來看看問題:
console.log(19571992547450991) // 19571992547450990 console.log(19571992547450991 === 19571992547450992) // true
如下圖所示:
同樣的原因,在 JavaScript 中 number 類型統(tǒng)一按浮點數(shù)處理,整數(shù)是按最大 54 位來算。
最大( 253 - 1,Number.MAX_SAFE_INTEGER、9007199254740991)
最小( -(253 - 1) ,Number.MIN_SAFE_INTEGER、*-9007199254740991*)
在浮點數(shù)計算中,有一些特定的小數(shù)情況可以避免舍入誤差。這是因為這些特定的小數(shù)可以精確地表示為二進制分數(shù),而不會導致舍入誤差。以下是一些常見的特定情況:
小數(shù)部分是2的負整數(shù)次冪:例如,0.5、0.25、0.125等。這些小數(shù)在二進制中可以精確表示,因此計算時不會出現(xiàn)舍入誤差。
小數(shù)部分是10的負整數(shù)次冪:例如,0.1、0.01、0.001等。盡管在十進制中無法精確表示,但在二進制中可以通過有限位數(shù)進行近似表示,并且通常不會引起明顯的舍入誤差。
四. 總結
浮點數(shù)精度問題是計算機科學中一個常見的問題,由于二進制無法精確表示某些十進制小數(shù),進行浮點數(shù)運算時可能會出現(xiàn)舍入誤差。為了解決這個問題,可以使用整數(shù)進行計算、使用專門的庫或者比較時使用誤差范圍。了解浮點數(shù)精度問題對于開發(fā)人員在處理浮點數(shù)運算時具有重要意義。
到此這篇關于JavaScript 浮點數(shù)精度問題小結的文章就介紹到這了,更多相關JavaScript 浮點數(shù)精度內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
解決在layer.open中使用時間控件laydate失敗的問題
今天小編就為大家分享一篇解決在layer.open中使用時間控件laydate失敗的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-09-09微信小程序?qū)崿F(xiàn)獲取用戶信息并存入數(shù)據(jù)庫操作示例
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)獲取用戶信息并存入數(shù)據(jù)庫操作,涉及微信小程序wx.request后臺數(shù)據(jù)交互及php數(shù)據(jù)存儲相關操作技巧,需要的朋友可以參考下2019-05-05JavaScript基礎進階之數(shù)組方法總結(推薦)
下面小編就為大家?guī)硪黄狫avaScript基礎進階之數(shù)組方法總結(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09Javascript靜態(tài)分頁(多個資料,靜態(tài)自動分頁)
看的處理是個不錯的想法與應用大家可以看下。2009-02-02JavaScript數(shù)組隨機排列實現(xiàn)隨機洗牌功能
這篇文章主要介紹了JavaScript數(shù)組隨機排列實現(xiàn)隨機洗牌功能的方法,涉及javascript中基于list.sort方法實現(xiàn)數(shù)組隨機排列的技巧,可應用于隨機洗牌,非常具有實用價值,需要的朋友可以參考下2015-03-03