# JS的浮点运算精度问题

float-operation-01

如上图所示,在JS中浮点数的运算会出现精度问题,更简单的有:

0.1 + 0.2 = 0.30000000000000004

究其原因,我们是以十进制输入的数字,但是计算机是以二进制运行的。程序中计算两个十进制的数,计算机需要将其转换为二进制,运算结束后再转为十进制返回,转换是不完美的。。

虽然JS中一般不涉及比较复杂的浮点数运算,但也不是绝对的用不到,还是要处理一下的。

# 一、简单的处理

如果业务中的数字不那么敏感,这个敏感的意思是指对数字的精度要求不高,而不是涉及支付、金融等。。

// + - * /
(num1 + num2).toFixed(2)// 保留两位小数
1
2

🤐简单的处理。。。

# 二、精度较高的处理

JS中小数运算会产生问题,但是整数运算并不会如此,可以将小数运算转换为整数运算。

首先需要获取一个浮点数的小数部分长度。

# 获取小数部分长度

// 获取小数部分长度
function getDecimalLength (num) {
  let len = 0;

  try {
    let _num = Number(num);// 可以转换使用科学计数法的数字
    let strArr = (_num + '').split('.');

    if (strArr.length === 2) {
      len = parseInt(strArr[1]) === 0 ? 0 : strArr[1].length;
    } else {
      len = 0;
    }
  } catch (e) {
    throw e;
  }

  return len;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 具体实现


 









 









 









 








// +
function add (num1, num2) {
  let dl1 = getDecimalLength(num1),// num1小数长度
    dl2 = getDecimalLength(num2),// num2小数长度
  	n;// 倍数

  n = Math.pow(10, Math.max(dl1, dl2));// 小数部分长度需用最长的那一个
  return Math.round(Number(num1) * n + Number(num2) * n) / n;
}

// -
function subtract (num1, num2) {
  let dl1 = getDecimalLength(num1),
  	dl2 = getDecimalLength(num2),
  	n;

  n = Math.pow(10, Math.max(dl1, dl2));
  return Math.round(Number(num1) * n - Number(num2) * n) / n;
}

// *
function multiply (num1, num2) {
  let dl1 = getDecimalLength(num1),
  dl2 = getDecimalLength(num2),
  n;

  n = Math.pow(10, Math.max(dl1, dl2));
  return (Number(num1) * n) * (Number(num2) * n) / (n * n);
}

// /
function divide (num1, num2) {
  let dl1 = getDecimalLength(num1),
  dl2 = getDecimalLength(num2),
  n;

  n = Math.pow(10, Math.max(dl1, dl2));
  return (Number(num1) * n) / (Number(num2) * n);
}
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

# 测试

add(0.1, 0.2);// 0.3
subtract(0.56, 0.19);// 0.37 -> 0.56 - 0.19 = 0.37000000000000005
multiply(0.142, 0.2);// 0.0284 -> 0.142 * 0.2 = 0.028399999999999998
divide(0.211111, 0.1);// 2.11111 -> 0.211111 / 0.1 = 2.1111099999999996
add(1e-1,2e-1);// 0.3
1
2
3
4
5

# 参考资料

Last Updated: 2 years ago