Javascript浮点数陷阱

来自三线的随记
Admin讨论 | 贡献2019年4月10日 (三) 21:34的版本

调试JavaScript代码的时候涉及了浮点数运算

出现了很奇怪的结果

> 5.1+2.55

> 7.6499999999999995

????????

祭出搜索引擎,获得文章

JavaScript 浮点数陷阱及解法 https://github.com/camsong/blog/issues/9

里面提到了两个解决方案

数据展示类

当你拿到 1.4000000000000001 这样的数据要展示时,建议使用 toPrecision 凑整并 parseFloat 转成数字后再显示,如下:

parseFloat(1.4000000000000001.toPrecision(12)) === 1.4  // True

封装成方法就是:

function strip(num, precision = 12) {
  return +parseFloat(num.toPrecision(precision));
}

为什么选择 12 做为默认精度?这是一个经验的选择,一般选12就能解决掉大部分0001和0009问题,而且大部分情况下也够用了,如果你需要更精确可以调高。

数据运算类

对于运算类操作,如 +-*/,就不能使用 toPrecision 了。正确的做法是把小数转成整数后再运算。以加法为例:

/**
* 精确加法
*/
function add(num1, num2) {
  const num1Digits = (num1.toString().split('.')[1] || ).length;
  const num2Digits = (num2.toString().split('.')[1] || ).length;
  const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits));
  return (num1 * baseNum + num2 * baseNum) / baseNum;
}

别的解决方案

还找到一个别的现成的JavaScript类库,例如

https://github.com/MikeMcl/decimal.js
https://www.html.cn/archives/7340/comment-page-1