JavaScript关于浮点计算精度缺失的问题

351 阅读2分钟

前言

为什么要写这一篇老生常谈的是文章呢?因为我在实际项目开发中确实被这个问题坑的一脸懵逼。踩坑,说实在的还是挺开心的,至少证明着自己哪里还存在不足,然后以此为铺垫,叙文记之

omg

为什么会出现这种问题?

计算机的二进制实现和位数限制有些数无法有限表示。就像一些无理数不能有限表示,如 圆周率 3.1415926…,1.3333… 等。JS 遵循IEEE 754规范,采用双精度存储(double precision),占用 64 bit。细节部分我就不具体阐述了,感兴趣的同学可自行百度了解,我在这里简单的记录一下我当时遇到的错误场景和解决方法。

omg

精度缺失例子🌰

因为我们公司是做支付的,所以难免会涉及到金额的计算,当时是这么一个场景,需要计算一个用户的付款金额加上小费金额,最后得出该订单的总金额

omg

初步一看,好像没多大的问题...窃喜.gif;想象是美好的,但现实是残酷的,在某一天,各种订单的错误信息铺面而来,商家的投诉也日益增加,我开始了bug排查之旅,此处省略排查步骤1万字...,在一次偶然的排雷过程中,我拿到这么一组数据,看到了其中的端倪;

omg

当时看到这个情况我是震惊的,这是什么情况,为什么会出现这种情况,各种黑人问号脸;然后在我合理的运用搜索引擎之后,才知道原来这是js这门语言设计时的缺陷

    // 比如一个很经典的案例
    var a = 0.1;
    var b = 0.2;
    console.log(a+b) ; // 0.30000000000000004
    

解决方案

运用BigNumber.js去解决

既然问题出现了,那我们就得着手去处理这个问题,为什么没有自己去写函数方法去解决这个问题呢?我是觉得BigNumber.js这个js库已经足够成熟,再加上我自身的能力原因,所以我就直接引用该js库了;

解决方案大致如下

  1. npm install --save bignumber.js => 先安装一波
  2. import {BigNumber} from 'bignumber.js' => import 引用
  3. 在具体的业务场景中合理使用

简单常用的计算方法:

  1. 加:plus
  // 原js计算 0.2 + 0.1 = 0.30000000000000004
    var num = new BigNumber(0.2);
    var result = num.plus(0.1);        
    console.log(num);       // 0.2
    console.log(result);    // 0.3
  1. 减:minus
  // 原js计算 0.3 - 0.1 = 0.19999999999999998
    var num = new BigNumber(0.3);
    var result = num.minus(0.1);        
    console.log(num);       // 0.3
    console.log(result);    // 0.2
  1. 乘:multipliedBy
  // 原js计算 1.13 * 100 = 112.999999999999
    var num = new BigNumber(1.13);
    var result = num.multipliedBy(100);        
    console.log(num);       // 1.13
    console.log(result);    // 113
  1. 除:modulo dividedBy
  // 原js计算 1 % 0.9 = 0.09999999999999998
    var num = new BigNumber(1);
    var result = num.modulo(0.9);        
    console.log(num);       // 1
    console.log(result);    // 0.1

相关文章

  1. juejin.cn/post/684490…
  2. mikemcl.github.io/bignumber.j…