您的当前位置:首页正文

js四舍五入和计算精度问题处理

2024-11-24 来源:个人技术集锦

js四舍五入和计算精度问题处理

js中加减乘除,部分数据会存在计算不准确。

错误计算

我使用的是big.js,基于big.js库封装了下工具方法,当然也可以用其他库,如mathjs/bignumber.js

方法

  • numberToFixed():四舍五入
  • numberMultiply:乘法
  • numberDiv():除法
  • numberPlus():加法
  • numberMinus():减法

示例

numberMultiply(0.2, 0.7) // 0.14 乘法
numberMultiply(0.2, ‘0.7’) // 0.14 可以是字符串类型的数字
numberMultiply(0.2, 0.7, 4, false) // ‘0.1400’

numberDiv(5, 2) // 2.5 除法
numberPlus(5, 2) // 7 加法
numberMinus(5, 2) // 3 减法

// 四舍五入
numberToFixed(12.225, 2) // 12.23
numberToFixed(12.225, 4, false) // ‘12.2250’

封装方法1

代码&使用示例:
numberUtil.ts

/**
 * @fileOverview 数值计算工具类
 * @date 2024-5-30
 */
import Big from 'big.js';
/**
 * 四舍五入
 * @param number 数字
 * @param precision 精度,不传则默认保留两位小数
 * @param isReturnNumber 是否返回数字类型,默认返回数字类型,否则返回字符串类型
 */
export function numberToFixed(number: number | string, precision = 2, isReturnNumber = true) {
  try {
    const bigNum = new Big(number).round(precision);
    // 直接返回数字类型
    if (isReturnNumber) return bigNum.toNumber().valueOf();
    // 返回字符串类型,不足位数用0补齐
    return bigNum.toFixed(precision).valueOf();
  } catch (e) {
    return '';
  }
}

type numberComputeType = 'times' | 'div' | 'plus' | 'minus';

/**
 * 数值计算
 * @param type
 * @param number1 数值1
 * @param number2 数值2
 * @param precision 精度,不传不处理精度
 * @param isReturnNumber 是否返回数字类型,默认返回数字类型,否则返回字符串类型
 */
function numberCompute(
  type: numberComputeType,
  number1: number | string,
  number2: number | string,
  precision: number | undefined,
  isReturnNumber: boolean | undefined
) {
  try {
    const bigNum = new Big(number1)[type](number2);
    const value = bigNum.toNumber().valueOf();
    if (precision === 0 || precision) return numberToFixed(value, precision, isReturnNumber);
    return value;
  } catch (e) {
    return '';
  }
}

/**
 * 数值计算
 * @params [数值1, 数值2, 精度?, 是否返回数字类型?]
 */
type numberComputeArgs = [string | number, string | number, number?, boolean?];

/**
 * 乘法
 * @param args 数值1, 数值2, 精度?, 是否返回数字类型?
 */
export const numberMultiply = (...args: numberComputeArgs) => numberCompute('times', ...args);

/**
 * 除法
 * @param args 数值1, 数值2, 精度?, 是否返回数字类型?
 */
export const numberDiv = (...args: numberComputeArgs) => numberCompute('div', ...args);
/**
 * 加法
 * @param args 数值1, 数值2, 精度?, 是否返回数字类型?
 */
export const numberPlus = (...args: numberComputeArgs) => numberCompute('plus', ...args);
/**
 * 减法
 * @param args 数值1, 数值2, 精度?, 是否返回数字类型?
 */
export const numberMinus = (...args: numberComputeArgs) => numberCompute('minus', ...args);

封装方法2(推荐-支持链式调用和使用Big.js方法)

  • 加减乘除,四舍五入 精度计算
  • 计算数值的同时进行四舍五入计算
  • 支持链式调用写法
  • new MyBig(xxx).value可直接调用 Big.js原始方法,该操作不会修改d1的值
  • 可选返回是数字类型还是字符串类型,默认返回数字类型
  • 如果已经是MyBig实例,则不再创建

代码&使用示例:

// MyBig方法,创建Big实例
function MyBig(x) {
  try {
    this.value = x instanceof MyBig ? x.value : new Big(x);
  } catch (e) {
    console.error("MyBig-error", e);
    this.value = new Big(0);
  }
}

// 四舍五入 round
MyBig.prototype.round = function (precision = 2) {
  this.precision = precision;
  this.value = this.value.round(precision);
  return this;
};

// 计算方法
function computedNumber(type) {
  return function (n, precision) {
    this.value = this.value[type](n);
    // 如果传入精度了,则进行四舍五入
    if (precision && precision !== 0) {
      this.round(precision);
    }
    return this;
  };
}
// 定义MyBig内要使用的方法
const computedTypes = {
  add: "add", // 加法 add
  sub: "sub", // 减法 sub
  div: "div", // 除法 div
  times: "times", // 乘法 times
};
Object.keys(computedTypes).forEach((key) => {
  MyBig.prototype[key] = computedNumber(computedTypes[key]);
});

// 使用方法
// 使用 new MyBig()创建MyBig示例
const d1 = new MyBig(12.225); // 创建实例
d1.round(); // 进行四舍五入 12.23
d1.add(0.27); // 加法 12.5
d1.sub(2.5); // 减法 10
d1.times(2); // 乘法 20
d1.div(4); // 乘法 5
d1.valueOf(); // 获取结果值

// 链式调用写法:
const d2 = new MyBig(12.225).round().add(0.27).sub(2.5).times(2).div(4).valueOf(); // 5

// d1.value可直接调用 Big.js方法,该操作不会修改d1的值
d1.value.div(2);

// 计算数值的同时进行四舍五入计算
const d3 = new MyBig(0.1225); // 创建实例
console.log(d3.add(0.1225, 2).valueOf()) // 0.25
显示全文