问题描述
众所周知,在 javasSript 中 0.1 + 0.3 会出现精度问题,那么其他小数相加会不会也有问题呢?还有相乘呢?
测试用代码和结果如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
   |  let arr = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]; for (let i = 0; i < arr.length; i++) {   let val1 = arr[i];   for (let j = i; j < arr.length; j++) {     let val2 = arr[j];     console.log(`${val1} + ${val2} = ${val1 + val2}`);   } }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  let arr = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]; for (let i = 0; i < arr.length; i++) {   let val1 = arr[i];   for (let j = i; j < arr.length; j++) {     let val2 = arr[j];     console.log(`${val1} * ${val2} = ${val1 * val2}`);   } }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  | 
解决方案
Number.EPSILON 解决相等判断的问题
如何解决 0.1 + 0.2 !== 0.3 的问题呢?
Number.EPSILON 是 es6 中新增的一个常量,用来表示一个最小的浮点数,这个值是 2 的-52 次方,也就是 2 的-52 次方的值,这个值可以用来判断两个浮点数是否相等。
所以可以自己实现一个判断浮点数相等的方法,如下:
1 2 3 4 5 6 7 8 9
   | 
 
  function isEqual(num1, num2) {   return Math.abs(num1 - num2) < Number.EPSILON; }
  console.log(0.1 + 0.2 === 0.3);  console.log(isEqual(0.1 + 0.2, 0.3)); 
 
  | 
目前该方法只能用作判断相等,不能让浮点数相加后的结果等于期望结果,如果需要浮点数相加后的结果等于期望结果,可以使用第三方库,比如 mathjs 库。
解决浮点数相互计算的问题
可以通过乘以一个倍数,去掉小数,然后相加,再除以这个倍数,来还原浮点数。
1 2 3 4 5 6 7
   | function add(num1, num2) {   const multiple = 10 ** 6;    return (num1 * multiple + num2 * multiple) / multiple; }
  console.log(0.1 + 0.2);  console.log(add(0.1, 0.2)); 
  | 
使用第三方库
最好的办法其实还是使用第三方库。不用自己造轮子,省时省精力还不易出错。
mathjs
mathjs 官网 
mathjs npm 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   | const mathjs = require("mathjs");
 
 
  let a1 = 0.1 + 0.2; console.log("原生相加结果:", a1); 
  let a2 = parseFloat(mathjs.add(mathjs.bignumber(0.1), mathjs.bignumber(0.2))); console.log("mathjs相加结果:", a2); 
 
  let b1 = 0.1 * 0.1; console.log("原生相乘结果:", b1); 
  let b2 = parseFloat(   mathjs.multiply(mathjs.bignumber(0.1), mathjs.bignumber(0.1)) ); console.log("mathjs相乘结果:", b2); 
  | 
decimal.js
decimal.js 官网 
decimal.js npm 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | const Decimal = require("decimal.js");
 
 
  let a1 = 0.1 + 0.2; console.log("原生相加结果:", a1); 
  let a2 = parseFloat(new Decimal(0.1).plus(0.2)); console.log("decimal.js相加结果:", a2); 
 
  let b1 = 0.1 * 0.1; console.log("原生相乘结果:", b1); 
  let b2 = parseFloat(new Decimal(0.1).times(0.1)); console.log("mathjs相乘结果:", b2); 
  |