最近在做小程序的一个项目 老大要求所有的计算出来的金钱数字都要保留两位小数点,自然而然想到了js的toFixed() 方法,然而既然写了这个文章结局肯定不想而知......闲言少叙 上代码
还是再说几句吧 好歹描述一下 业务场景 复现一下过程, 过程是这个样子滴
后台设置了折扣的金额 8.745折 我这个时候订单的金额是10RMB 结果就是
let discount = 8.745; // 优惠折扣
let money = 10;// 订单金额
let price = discount/10*10; // 实际支付金额
console.log(price) // 实际支付的金额 8.745RMB
/***需求 (保留两位小数)***/
// 最开始的天真想法
let price = (discount/10*10).toFixed(2)
console.log(price) // 8.74
传到后台发现后台校验的金额和前台传的对不上......尴尬的一比 然后开始一顿笔算,和后台对结果,后来发现了问题 后台的结果是 8.75 前台是8.74 差了一分钱,发现前台计算出来的结果保留两位小数之后的值没有四舍五入 ,可是我又在想 toFixed() 是四舍五入的啊 为此 去测试了一下
(8.755).toFixed(2) // 8.76
(8.745).toFixed(2) // 8.74
(8.746).toFixed(2) // 8.75
得出来的解困就是这样 在3为小数的情况下
第二位小数小于5 第三位小数<=5 结果是不四舍五入的
这就尴尬了啊!
后来弄明白了是js计算的bug,js计算浮点数精度丢失的问题 网上的库解决这个一搜一大堆,但是咱们的需求是保留两位小数啊 所以结合一下...
接下来就说一下小老弟的解决办法
function accDiv(arg1,arg2){
var t1=0,t2=0,r1,r2;
try{t1=arg1.toString().split(".")[1].length}catch(e){}
try{t2=arg2.toString().split(".")[1].length}catch(e){}
with(Math){
r1=Number(arg1.toString().replace(".",""))
r2=Number(arg2.toString().replace(".",""))
return accMul((r1/r2),pow(10,t2-t1));
}
}
// 乘法
function accMul(arg1,arg2)
{
var m=0,s1=arg1.toString(),s2=arg2.toString();
try{m+=s1.split(".")[1].length}catch(e){}
try{m+=s2.split(".")[1].length}catch(e){}
return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)
}
/**
以上是网上copy出来的
以下是我的
**/
function toFixedTwo(n){
if(!isNaN(n)){
console.error("Error:n not is Number")
return false
}
return (Math.round(accMul(n,100))/100).toFixed(2)
}
也算是历经磨难解决了吧!
在js浮点数计算精度丢失问题导致结果异常和不准确 也是坑了我好几次了
ps:题外话 四月不减肥 五月徒伤悲 减肥开始了!!