十进制转二进制

整数采用 除2取余(由下往上)的方式,
57

57 / 2 = 28 … 1 28 / 2 = 14 … 0 14 / 2 = 7 … 0 7 / 2 = 3 … 1 3 / 2 = 1 … 1 1

111001

26

26 / 2 = 13 … 0 13 / 2 = 6 … 1 6 / 2 = 3 … 0 3 / 2 = 1 … 1 1

11010

小数采用 乘2取整(由上往下)的方式
0.1

.1 2 = 0.2 … 0 .2 2 = 0.4 … 0 .4 2 = 0.8 … 0 .8 2 = 1.6 … 1 .6 2 = 1.2 … 1 .2 2 = 0.4 … 0 .4 2 = 0.8 … 0 .8 2 = 1.6 … 1 .6 2 = 1.2 … 1 .2 2 = 0.4 … 0 .4 * 2 = 0.8 … 0 …

0.0001100110011001100110011001100 … 11001100

为什么会出现精度损失的情况

JavaScript 使用 Number 类型来表示数字(整数或浮点数),遵循 IEEE 754 标准,通过 64 位来表示一个数字。
两数相加时,会先转换成二进制

0.1 和 0.2 转换为二进制的时候尾数会无限循环

0.1 -> 0.0001100110011001100110011001100110011001100110011001101 0.2 -> 0.0011001100110011001100110011001100110011001100110011010

然后进行对阶运算,JS 引擎会对二进制进行截断,所以造成精度损失。

精度丢失可能出现在进制转换和对阶运算中。 如果不考虑精度,还可以用 toFixed 进行进制转化。 Number.parseFloat(x).toFixed(2);

如何解决精度丢失问题?

将数字转为整数

  1. function add(num1, num2) {
  2. const num1Digits = (num1.toString().split('.')[1] || '').length;
  3. const num2Digits = (num2.toString().split('.')[1] || '').length;
  4. const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits));
  5. return (num1 * baseNum + num2 * baseNum) / baseNum;
  6. }

但是这种方法对大数支持并不好。

使用第三方库

  • Math.js

  • Big.js

    字符串模拟运算

    可以考虑使用字符串模拟运算。

正确的比较方法

 Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON