vue中使用decimal.js对前端数值类型进行高精度计算

需求背景:由于一些场景我们需要在前端JavaScript进行数值计算,且对精度要求比较严谨,而前端数值是浮点类型,直接使用计算可能会产生一系列的精度问题,常见的浮点运算问题,比如精度损失等;所以例如涉及到一些金额计算等,需要进行高精度处理。

解决方案:

(1)可以把数值计算部分逻辑交给后端接口来完成,但是需增加一次网络请求开销(比较适用于需同时请求后端接口的场景)。

(2)无需请求后端接口,数据计算部分逻辑完全由前端进行,使用一些高精度处理的第三方JS库,比如decimal.js等(这里主要介绍decimal.js库)



npm 或 yarn安装引用decimal.js库:

//npm安装
npm install --save decimal.js(低版本-v4 及以下)
或
npm install decimal.js(高版本-npm v5及以上版本中)

//yarn安装
yarn add decimal.js

//引入
//Node.js 
var Decimal = require('decimal.js')

//ES6 方式
import { Decimal } from 'decimal.js'



下面是一些decimal.js【加减乘除】计算的使用案例:

methods: {
  handleDecimalData() {
      //加法
      var a1 = 0.13
      var b1 = 0.25
      let c1 = new Decimal(a1).add(new Decimal(b1)) 
      console.log("加法运算 a1 + b1 =",a1 + b1)
      console.log("使用decimal.js a1 + b1 =",c1.toString())
      //减法
      var a2 = 1.0
      var b2 = 0.99
      let c2 = new Decimal(a2).sub(new Decimal(b2)) 
      console.log("减法运算 a2 - b2 =",a2 - b2)
      console.log("使用decimal.js a2 - b2 =",c2.toString())
      //乘法
      var a3 = 1.01
      var b3 = 1.02
      let c3 = new Decimal(a3).mul(new Decimal(b3)) 
      console.log("乘法运算 a3 * b3 = ", a3 * b3)
      console.log("使用decimal.js a3 * b3 = ",c3.toString())
      //除法
      var a4 = 0.033
      var b4 = 10
      let c4 = new Decimal(a4).div(new Decimal(b4)) 
      console.log("除法运算 a4 / b4 = ", a4 / b4)
      console.log("使用decimal.js a4 / b4 = ",c4.toString())
  }
} 



对计算结果的一些处理方法:

js//四舍五入保留2位小数
total() {
  let price = new Decimal(this.itemPrice);
  let quantity = new Decimal(this.quantity);
  let total = price.mul(quantity);
  return total.toDecimalPlaces(2,Decimal.ROUND_HALF_UP).toString();
}

//向上取整
let value = new Decimal('123.456');
let ceilValue = value.ceil();
console.log(ceilValue.toString()); // 输出 "124"

//向下取整
let value = new Decimal('123.456');
let floorValue = value.floor();
console.log(floorValue.toString()); // 输出 "123"

/*
  保留小数部分的取整
  如果你需要保留小数部分,可以使用 toDecimalPlaces 方法结合 rounding 参数来实现向上或向下取整。
*/

//向上取整保留2位小数
let value = new Decimal('123.456');
let ceilValue = value.toDecimalPlaces(2, Decimal.ROUND_CEIL);
console.log(ceilValue.toString()); // 输出 "123.46"

//向下取整保留2位小数
let value = new Decimal('123.456');
let floorValue = value.toDecimalPlaces(2, Decimal.ROUND_FLOOR);
console.log(floorValue.toString()); // 输出 "123.45"

/**
 * 格式化数值,添加千位分隔符
 * @param {具体value数值} value
 * @param {保留几位小数:默认为两位小数} decimals 
 * @param {舍入模式:默认为四舍五入} rounding 
 * @returns 
 */
export function formatNumber(value, decimals = 2,rounding=Decimal.ROUND_HALF_UP) {
  if(typeof value==='string' && value==''){
    return ''
  }

  if (!(value instanceof Decimal)) {
    value = new Decimal(value);
  }

  const parts = value.toDecimalPlaces(decimals,rounding).toString().split('.');
  parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
  return parts.join('.');
}
//calcResult可以是字符串类型的数值
console.log(formatNumber(calcResult));

注意:

(1)最终计算结果最好不要转成.toNumber(),毕竟还是浮点类型,可以直接.toString()转成字符串来使用。

(2)还有这个.toFixed()这个四舍五入还是少用(有些场景结果是不对的),对于计算结果要求比较严谨的场景,还是使用decimal.js的api方法实现四舍五入等处理。


参考博文链接:https://www.cnblogs.com/morango/p/14555507.html#!comments
posted @ 2024-09-29 16:56  QAQhong  阅读(222)  评论(0编辑  收藏  举报