likes
comments
collection
share

聊一聊Javascript中的数字精度丢失问题

作者站长头像
站长
· 阅读数 49

前言

在Javascript中,所有的数字都是以64位浮点数的形式存储的。这意味着Javascript可以表示的最大和最小的数字分别是2的1024次方和2的-1023次方。然而,这也意味着Javascript不能精确地表示一些十进制的小数,比如0.10.2。这可能会导致一些意想不到的结果,比如:

console.log(0.1 + 0.2); // 0.30000000000000004  
console.log(0.1 + 0.2 == 0.3); // false  

为什么

在计算机中,所有的数字都是以二进制的形式来存储和处理的。而在二进制中,有些数是无法精确表示的,例如 0.1 就是一个无限循环小数,转换成二进制之后是 0.0001100110011001……,因为计算机的存储精度是有限的,无法精确存储这样的数字,所以在进行小数运算时,可能会发生舍入误差,从而导致精度丢失。

0.10.2在二进制中都是无限循环小数,所以在转换为64位浮点数时会有一定的舍入误差。这种误差在进行数学运算时会被放大,从而导致前言中的计算结果不准确。

解决方案

那么,如何解决这个问题呢?有几种常用的方法:

  • 使用整数代替小数,比如把0.1变成1,把0.2变成2,然后再除以10得到正确的结果。

    console.log((1 + 2) / 10); // 0.3
    
  • 使用第三方的库,比如Big.jsDecimal.js,它们可以提供任意精度的十进制运算。

    Big.js

    安装方式

    npm install big.js
    

    使用方式

    // 引入Big.js库
    const Big = require('big.js');
    
    // 使用Big.js进行任意精度的加法运算
    const a = new Big('0.1');
    const b = new Big('0.2');
    const c = a.plus(b);
    console.log(c.toString()); // 输出 '0.3'
    

    Decimal.js

    安装方式

    npm install decimal.js
    

    使用方式

    // 引入Decimal.js
    const Decimal = require('decimal.js');
    
    // 创建Decimal对象
    const a = new Decimal(0.1);
    const b = new Decimal('0.2');
    
    // 进行计算
    const c = a.plus(b); // 0.3
    
    // 输出结果
    console.log(c.toString()); // '0.3'
    

    需要注意的是,在使用Decimal.js时,应该尽量避免使用JavaScript原生的数字类型,以免出现精度丢失的问题。

  • 使用ES6中引入的Number.EPSILON,它表示最小的可以被表示的正数,可以用来判断两个浮点数是否相等。

    // 判断两个浮点数是否相等
    function isEqual(num1, num2) {
      return Math.abs(num1 - num2) < Number.EPSILON;
    }
    
    console.log(isEqual(0.1 + 0.2, 0.3)); // 输出 true
    

总结

JavaScript中64位浮点数不能准确表示十进制小数,使用整数替代小数或Big.js/Decimal.js库执行任意精度运算,或使用Number.EPSILON判断两个浮点数是否相同。

转载自:https://juejin.cn/post/7231374594815541305
评论
请登录