众所周知,js在计算浮点数时候,结果可能会不准确。比如:(在chrome中的运算结果) 2.2 + 2.1 = 4.300000000000001 2.2 - 1.9 = 0.30000000000000027 2.2 * 2.2 = 4.840000000000001 2.1 / 0.3 = 7.000000000000001
网上流传的优化后的代码如下(有问题的代码,请勿使用)
function add(a, b) { var c, d, e; try { c = a.toString().split(".")[1].length; } catch (f) { c = 0; } try { d = b.toString().split(".")[1].length; } catch (f) { d = 0; } return e = Math.pow(10, Math.max(c, d)), (a * e + b * e) / e; } function sub(a, b) { var c, d, e; try { c = a.toString().split(".")[1].length; } catch (f) { c = 0; } try { d = b.toString().split(".")[1].length; } catch (f) { d = 0; } return e = Math.pow(10, Math.max(c, d)), (a * e - b * e) / e; } function mul(a, b) { var c = 0, d = a.toString(), e = b.toString(); try { c += d.split(".")[1].length; } catch (f) {} try { c += e.split(".")[1].length; } catch (f) {} return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c); } function div(a, b) { var c, d, e = 0, f = 0; try { e = a.toString().split(".")[1].length; } catch (g) {} try { f = b.toString().split(".")[1].length; } catch (g) {} return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), c / d * Math.pow(10, f - e); } 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354原理就是将浮点数转化为整数来计算。
但是上面的优化方法真的解决问题了吗,我们可以简单做下测试。 测试代码如下:(测试运算中加法)
function test(){ var a = (Math.random() * 100).toFixed(2) - 0; var b = (Math.random() * 1000).toFixed(2) - 0; var result = add(a, b); if ((result + '').length > 10) { console.error('被加数:'+a,'加数:'+b, '结果:'+result); return; } setTimeout(function() { test(); }, 10); } test(); 12345678910111213浏览器控制台很快就打印了结果,说明被测试的加法运算代码存在运算不准确的问题。 测试运行结果:
既然上面的代码有问题,那么出错的点在哪里,我们就以计算错误的数字来调试代码。 被加数:19.36 加数:601.19 结果:620.5500000000001 调试的过程及结果如下: 我们发现原来是其中的乘法计算错误。
网上有一些版本你会发现在最终返回结果的时候加上了toFixed,这是一种解决方法。 另外既然是乘法出错,我们何不将乘法换成优化后的乘法了。比如修改后的加法如下:
function add(a, b) { var c, d, e; try { c = a.toString().split(".")[1].length; } catch (f) { c = 0; } try { d = b.toString().split(".")[1].length; } catch (f) { d = 0; } return e = Math.pow(10, Math.max(c, d)), (mul(a, e) + mul(b, e)) / e; } 1234567891011121314然后用上面的方法进行测试,等了”一天“,控制台也没打印了。说明这次真的把问题解决了。