分析
JavaScript 只有一種數字類型 Number
,而且在Javascript中所有的數字都是以IEEE-754標準格式表示的。 浮點數的精度問題不是JavaScript特有的,因為有些小數以二進位表示位元是無窮的:
十進位 二進位0.1 0.0001 1001 1001 1001 ...0.2 0.0011 0011 0011 0011 ...0.3 0.0100 1100 1100 1100 ...0.4 0.0110 0110 0110 0110 ...0.5 0.10.6 0.1001 1001 1001 1001 ...
所以比如 1.1
,其程式實際上無法真正的表示 ‘1.1’,而只能做到一定程度上的準確,這是無法避免的精度丟失:
1.09999999999999999
在JavaScript中問題還要複雜些,這裡只給一些在Chrome中測試資料:
輸入 輸出1.0-0.9 == 0.1 False1.0-0.8 == 0.2 False1.0-0.7 == 0.3 False1.0-0.6 == 0.4 True1.0-0.5 == 0.5 True1.0-0.4 == 0.6 True1.0-0.3 == 0.7 True1.0-0.2 == 0.8 True1.0-0.1 == 0.9 True
解決
那如何來避免這類 1.0-0.9 != 0.1
的非bug型問題發生呢?下面給出一種目前用的比較多的解決方案, 在判斷浮點運算結果前對計算結果進行精度縮小,因為在精度縮小的過程總會自動四捨五入:
(1.0-0.9).toFixed(digits) // toFixed() 精度參數須在 0 與20 之間,返回資料類型為stringparseFloat((1.0-0.9).toFixed(10)) === 0.1 // 結果為TrueparseFloat((1.0-0.8).toFixed(10)) === 0.2 // 結果為TrueparseFloat((1.0-0.7).toFixed(10)) === 0.3 // 結果為TrueparseFloat((11.0-11.8).toFixed(10)) === -0.8 // 結果為True
方法提煉
// 通過isEqual工具方法判斷數值是否相等function isEqual(number1, number2, digits){digits = digits == undefined? 10: digits; // 預設精度為10return number1.toFixed(digits) === number2.toFixed(digits);}isEqual(1.0-0.7, 0.3); // return true// 原生擴充方式,更喜歡物件導向的風格Number.prototype.isEqual = function(number, digits){digits = digits == undefined? 10: digits; // 預設精度為10return this.toFixed(digits) === number.toFixed(digits);}(1.0-0.7).isEqual(0.3); // return true
轉載:http://madscript.com/javascript/javscript-float-number-compute-problem/