JS精度使用小结

157 阅读2分钟

背景: 由于JS使用的是IEEE 754双精度浮点格式,某些小数没法用二进制精确表示出来,所以JS计算时存在精度丢失的问题。

如何规避这个问题:

  • 将小数转成整数再计算
  • 在对精度要求不高的情况下,可以将数据四舍五入或者toFixed()保留指定的位数
  • 如果对精度要求比较高,可以引用库来计算,比如decimal.js

Decimal.js 常用API

  • 构造函数 Decimal(value),返回一个新的Decimal对象的实例

    value: number|string|Decimal,

    如果数据包含合法的前缀也可以初始化(十进制0x或者0X,二进制0b或者0B,八进制0o或者0O)

    指数型数据

  • add 加法 .add(x,y)

    plus 别名

    a = Decimal.add(x,y)
    b = new Decimal(x).plus(y)
    a.equals(b)  // true
    
  • sub 减法 .sub(x,y)

    a = Decimal.sub(x,y)
    b = new Decimal(x).sub(y)
    a.equals(b)  //true
    
  • mul 乘法 .mul(x,y)

    a = Decimal.mul(x,y)
    b = new Decimal(x).mul(y)
    a.equals(b)   //true
    
  • div 除法 .div(x,y)

    a = Decimal.div(x,y)
    b = new Decimal(x).div(y)
    a.equals(b)  //true
    
  • max 最大值 返回参数中的最大值,类型为Decimal

    r = Decimal.max(x,y,z)
    
  • min 最小值 返回参数中的最小值,类型为Decimal

    r = Decimal.min(x,y,z)
    
  • ceil 向上取整

    a = Decimal.ceil(x)
    b = new Decimal(x).ceil()
    a.equals(b)  //true
    
  • floor 向下取整

    a = Decimal.floor(x)
    b = new Decimal(x).floor()
    a.equals(b)  //true
    
  • round 四舍五入

    a = Decimal.round(x)
    b = new Decimal(x).round()
    a.equals(b)   //true
    
  • set 设置 .set(object)

    为指定的Decimal构造函数配置全局的参数,如果object的·defaults·为true,则所有为指定的属性都将重置为对应的默认值

    Decimal.set({
        precision: 20,
        rounding: 4,
        defaults:true
    })
    

    可以使用set配置的属性有

    • precision 精度

      number:整数,包含1到1e+9

      默认值:20,表示运算结果最大的有效位数是20,返回的计算结果都将四舍五入为有效的精度

    • rounding 舍入

      number:整数 包含0到8

      默认值:4(ROUND_HALF_UP 四舍五入)

      ROUND_UP0远离零
      ROUND_DOWN1靠近零
      ROUND_CEIL2靠近正Infinity
      ROUND_FLOOR3靠近负Infinity
      ROUND_HALF_UP4向上靠近最近值,如果等距就四舍五入。
      ROUND_HALF_DOWN5向下靠近最近值,如果等距就舍入为0。
      ROUND_HALF_EVEN6最近值四舍五入
      ROUND_HALF_CEIL7最近值靠近+Infinity
      ROUND_HALF_FLOOR8最近值靠近-Infinity
      EUCLID9不是舍入模式
  • 实例方法

    • plus 加

    • minus 减

    • times 乘

    • dividedBy 除

      x = new Decimal(355)
      y = new Decimal(113)
      x.dividedBy(y)  // 按照设置的rounding和precision,返回一个新的Decimal对象
      

    PS:实际项目中,由于大数计算,需要精度准确,引入了decimal.js

    由于计算出来的数据过大,直接以指数型展示在页面上在,所以需要设置精度,这样还是以普通数据形式展示在页面上

    Decimal.set({precision:30})