一文解決前端JS小數(shù)運算精度問題
前言
在做項目的時候,前端需要在表格的底部做一個匯總的功能,在采用reduce對當(dāng)前屬性所有值匯總時,發(fā)現(xiàn)匯總結(jié)果存在好長的小數(shù)位,本以為后端的數(shù)據(jù)就存在精度這么小的數(shù)據(jù),后來,檢查發(fā)現(xiàn)后端精度只有三位小數(shù),但前端計算結(jié)果為什么會這樣呢?
JS存在精度問題
在控制臺可以試一下 0.1 + 0.2 的結(jié)果是0.30000000000000004 js的運算下 0.1 + 0.2 != 0.3
由于計算機在存儲和計算數(shù)字的時候,使用的是二進制形式,有些十進制數(shù)據(jù)再轉(zhuǎn)換成二進制時,無法精確表示。
JS在數(shù)字運算的時候,當(dāng)存在浮點數(shù)的運算時,就有可能會出現(xiàn)精度誤差,有些小數(shù)無法用二進制精確表示。
JavaScript采用的是雙精度(64位)浮點運算規(guī)則,遵循的是IEEE二進制浮點數(shù)算法標(biāo)準。其中有1位用作符號位,11位為階碼,尾數(shù)有52位。有興趣詳細了解的可以查閱相關(guān)資料。
比如 十進制0.1 -> 二進制表示為0.0001 1001 1001 1001...(1100循環(huán)) 十進制0.2 -> 二進制表示為0.0011 0011 0011 0011...(0011循環(huán)) EEE 754 標(biāo)準的 64 位雙精度浮點數(shù)的小數(shù)部分最多支持53位二進制位,所以兩者相加之后得到二進制為: 0.1 + 0.2 = 0.0100110011001100110011001100110011001100110011001100 因浮點數(shù)小數(shù)位的限制而截斷的二進制數(shù)字,再轉(zhuǎn)換為十進制,就成了0.30000000000000004。
解決方案
思路:
- 將小數(shù)轉(zhuǎn)化成整數(shù)進行計算,規(guī)避浮點數(shù)運算問題。
- 整數(shù)的加減乘運算結(jié)果不會出現(xiàn)浮點數(shù),不會存在精度問題,但除法會出現(xiàn)浮點數(shù),因此用toFixed()方法截掉無效的小數(shù)位。
- 將string轉(zhuǎn)回number輸出
/** 封裝一個公共方法numberCalculate() 用于浮點數(shù)運算 */
//num1 num2傳入兩個值 symbol +-*/符號
numberCalculate(num1: number, num2: number, symbol: string) {
var str1 = num1.toString(), str2 = num2.toString(), result, str1Length, str2Length
try {
//獲取小數(shù)點后的精度
str1Length = str1.split('.')[1].length
}
catch (error) {
//解決整數(shù)沒有小數(shù)點方法
str1Length = 0
}
try {
str2Length = str2.split('.')[1].length
} catch (error) {
str2Length = 0
}
// 取兩個數(shù)的最小精度,即小數(shù)點后數(shù)字的最大長度
var maxLen = Math.max(str1Length, str2Length)
// step將兩個數(shù)都轉(zhuǎn)化為整數(shù)至少小數(shù)點后移多少位
var step = Math.pow(10, maxLen)
switch (symbol) {
case "+":
// toFixed()根據(jù)最小精度截取運算結(jié)果
result = ((num1 * step + num2 * step) / step).toFixed(maxLen)
break;
case "-":
result = ((num1 * step - num2 * step) / step).toFixed(maxLen)
break;
case "*":
result = (((num1 * step) * (num2 * step)) / step / step).toFixed(maxLen)
break;
case "/":
result = ((num1 * step) / (num2 * step)).toFixed(maxLen)
break;
default:
break;
}
// 由于toFixed方法返回結(jié)果是字符串,還需要轉(zhuǎn)回number輸出
return Number(result)
}
0.1 + 0.2的計算,就可以調(diào)用numberCalculate(0.1,0.2,'+')進行計算了。
以上就是一文解決前端JS小數(shù)運算精度問題的詳細內(nèi)容,更多關(guān)于JS小數(shù)運算精度的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
DOM節(jié)點的替換或修改函數(shù)replaceChild()用法實例
這篇文章主要介紹了DOM節(jié)點的替換或修改函數(shù)replaceChild()用法,實例分析了replaceChild()替換DOM節(jié)點的使用技巧,需要的朋友可以參考下2015-01-01
javascript模擬select,jselect的方法實現(xiàn)
由于主流瀏覽器對select元素渲染不同,所以在每種瀏覽器下顯示也不一樣,最主要的是默認情況下UI太粗糙,即使通過css加以美化也不能達到很美觀的效果2012-11-11

