众所周知,javascript对于浮点数的运算一直都是有问题的,比如0.2+0.1 结果是 0.30000000000000004。
下面是我的解决方案,先贴代码了:
var calMath = (function() { var isFloat = function(a) { var reg = /d.d+/g return reg.test(a) } var getFloatDigit = function(a) { var digit, len a = a.toString() digit = a.split(".") len = digit[1] == undefined ? 0 : digit[1].length return len } var allArithmetic = function(type, a, b) { var c, gfd_a, gfd_b, baseLen, baseMulti var a = Number(a), b = Number(b) if (isFloat(a) || isFloat(b)) { gfd_a = getFloatDigit(a) gfd_b = getFloatDigit(b) baseLen = gfd_a >= gfd_b ? gfd_a : gfd_b baseMulti = Math.pow(10, baseLen) a = type != "add" ? Number(a.toString().replace(".", "")) : a b = type != "add" ? Number(b.toString().replace(".", "")) : b if (type == "add") { c = ((a * baseMulti + b * baseMulti) / baseMulti).toFixed(baseLen) } else if (type == "multi") { c = (a * b) / Math.pow(10, gfd_a + gfd_b) } else if (type == "divi") { c = ((a / b) * Math.pow(10, gfd_b - gfd_a)) } } else { if (type == "add") { c = a + b } else if (type == "multi") { c = a * b } else if (type == "divi") { c = a / b } } return c } return { add: function(a, b) { return allArithmetic("add", a, b) }, sub: function(a, b) { return allArithmetic("add", a, -b) }, multi: function(a, b) { return allArithmetic("multi", a, b) }, divi: function(a, b) { return allArithmetic("divi", a, b) } } })()
思路就是:
1. 判定是否是浮点数。
2. 如果不是浮点数,就选择常规的运算方法。
3. 如果是浮点数,则先取浮点数后面个数(即小数点的位数)。
4. 如果是浮点数的加减法运算,则比较他们小数点后的位数,取较大的那个,暂且称之为n,这个数有什么用呢?就是先让我们的浮点数都变成整数(小数乘以10的n次方),然后在重新变成浮点数(结果再除以10的n次方),整数做加减法总没事了吧?其实并不一定,有些情况,浮点数乘以10的次方时,出来的数也会有“尾巴”,但是这个“尾巴”的误差相对来说比较小,所以我们利用toFixed(n)来处理掉它就ok了。
5. 如果是浮点数的乘法运算,其实思路跟上面的类似,先将他们小数点后的位数相加,取得的值继续叫他小n吧,小n暂且不管他,我们这里换种让浮点数变成整数的方式,就是直接把小数点给去掉,理由就是刚刚在加减法时提到的,如果用10的n次方让小数变整数,其实有可能出现误差很小的浮点数的,那在加减法中我们可以有补救措施,但是在乘法中,一个点0.00000000x的小数出现了之后,再补救就不可能了。那我们这里的小n有什么用呢,当然是把整数再变回小数啦。
6. 如果是浮点数的除法运算,思路跟乘法基本一致,看着代码自己思考吧。
console.log(calMath.add(0.2,0.1)) //结果是0.3哦