一、1. 生产环境推荐使用 decimal.js - 功能完整,性能良好
使用第三方数学计算库( decimal.js)
csharp
复制代码
npm install decimal.js
封装计算方法
typescript
复制代码
import Decimal from "decimal.js-light"
// 内部工具:安全生成 Decimal
function toDecimal(value: string | number | null | undefined): Decimal {
if (value === null || value === undefined || value === "" || isNaN(Number(value))) {
return new Decimal(0)
}
return new Decimal(value)
}
// 加
export function decimal_add(x: string | number, y: string | number): number {
return toDecimal(x).plus(toDecimal(y)).toNumber()
}
// 减
export function decimal_sub(x: string | number, y: string | number): number {
return toDecimal(x).sub(toDecimal(y)).toNumber()
}
// 除
export function decimal_div(x: string | number, y: string | number): number {
const divisor = toDecimal(y)
if (divisor.isZero()) return 0 // 避免除 0
return toDecimal(x).div(divisor).toNumber()
}
// 乘
export function decimal_mul(x: string | number, y: string | number): number {
return toDecimal(x).mul(toDecimal(y)).toNumber()
}
or直接使用
xml
复制代码
<template>
<div>
<input v-model.number="num1" type="number" />
<input v-model.number="num2" type="number" />
<button @click="calculate">计算</button>
<p>结果:{{ result }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Decimal } from 'decimal.js'
const num1 = ref(0.1)
const num2 = ref(0.2)
const result = ref(0)
const calculate = () => {
// 使用 Decimal 进行精确计算
const a = new Decimal(num1.value)
const b = new Decimal(num2.value)
// 加法
result.value = a.plus(b).toNumber()
// 其他运算
// const subtract = a.minus(b).toNumber() // 减法
// const multiply = a.times(b).toNumber() // 乘法
// const divide = a.dividedBy(b).toNumber() // 除法
}
</script>
二、使用big.js
复制代码
npm install big.js
javascript
复制代码
// utils/bigCalculator.js
import Big from 'big.js'
/**
* 精确加法
* @param {number|string} a - 第一个数
* @param {number|string} b - 第二个数
* @param {number} [precision] - 精度(小数位数)
* @returns {number} 计算结果
*/
export function add(a, b, precision) {
try {
const result = new Big(a).plus(new Big(b))
return precision !== undefined ? round(result, precision) : result.toNumber()
} catch (error) {
console.error('加法计算错误:', error)
return NaN
}
}
/**
* 精确减法
* @param {number|string} a - 被减数
* @param {number|string} b - 减数
* @param {number} [precision] - 精度(小数位数)
* @returns {number} 计算结果
*/
export function subtract(a, b, precision) {
try {
const result = new Big(a).minus(new Big(b))
return precision !== undefined ? round(result, precision) : result.toNumber()
} catch (error) {
console.error('减法计算错误:', error)
return NaN
}
}
/**
* 精确乘法
* @param {number|string} a - 第一个数
* @param {number|string} b - 第二个数
* @param {number} [precision] - 精度(小数位数)
* @returns {number} 计算结果
*/
export function multiply(a, b, precision) {
try {
const result = new Big(a).times(new Big(b))
return precision !== undefined ? round(result, precision) : result.toNumber()
} catch (error) {
console.error('乘法计算错误:', error)
return NaN
}
}
/**
* 精确除法
* @param {number|string} a - 被除数
* @param {number|string} b - 除数
* @param {number} [precision] - 精度(小数位数)
* @returns {number} 计算结果
*/
export function divide(a, b, precision) {
try {
if (new Big(b).eq(0)) {
throw new Error('除数不能为零')
}
const result = new Big(a).div(new Big(b))
return precision !== undefined ? round(result, precision) : result.toNumber()
} catch (error) {
console.error('除法计算错误:', error)
return NaN
}
}
/**
* 四舍五入
* @param {Big} value - big.js 对象
* @param {number} precision - 小数位数
* @returns {number} 四舍五入后的值
*/
function round(value, precision) {
return Number(value.toFixed(precision))
}
/**
* 链式计算器
*/
export class Calculator {
constructor(initialValue = 0) {
this.value = new Big(initialValue)
}
add(num) {
this.value = this.value.plus(new Big(num))
return this
}
subtract(num) {
this.value = this.value.minus(new Big(num))
return this
}
multiply(num) {
this.value = this.value.times(new Big(num))
return this
}
divide(num) {
if (new Big(num).eq(0)) {
throw new Error('除数不能为零')
}
this.value = this.value.div(new Big(num))
return this
}
result(precision) {
return precision !== undefined
? Number(this.value.toFixed(precision))
: this.value.toNumber()
}
}
三、 简单场景可使用自定义工具函数 - 减少依赖
1. 基础版本工具函数
php
复制代码
// utils/precisionCalculator.js
/**
* 获取数字的小数位数
* @param {number|string} num - 数字
* @returns {number} 小数位数
*/
function getDecimalPlaces(num) {
const numStr = num.toString()
const decimalIndex = numStr.indexOf('.')
return decimalIndex === -1 ? 0 : numStr.length - decimalIndex - 1
}
/**
* 获取多个数字中最大的小数位数
* @param {...number} numbers - 数字
* @returns {number} 最大小数位数
*/
function getMaxDecimalPlaces(...numbers) {
return Math.max(...numbers.map(num => getDecimalPlaces(num)))
}
/**
* 将数字转换为整数(放大倍数)
* @param {number} num - 数字
* @param {number} decimalPlaces - 小数位数
* @returns {number} 整数
*/
function toInteger(num, decimalPlaces) {
return Math.round(num * Math.pow(10, decimalPlaces))
}
/**
* 精确加法
* @param {number} a - 第一个数
* @param {number} b - 第二个数
* @param {number} [precision] - 精度(保留小数位数)
* @returns {number} 计算结果
*/
export function add(a, b, precision) {
const maxDecimal = getMaxDecimalPlaces(a, b)
const multiplier = Math.pow(10, maxDecimal)
const result = (toInteger(a, maxDecimal) + toInteger(b, maxDecimal)) / multiplier
return precision !== undefined ? round(result, precision) : result
}
/**
* 精确减法
* @param {number} a - 被减数
* @param {number} b - 减数
* @param {number} [precision] - 精度(保留小数位数)
* @returns {number} 计算结果
*/
export function subtract(a, b, precision) {
const maxDecimal = getMaxDecimalPlaces(a, b)
const multiplier = Math.pow(10, maxDecimal)
const result = (toInteger(a, maxDecimal) - toInteger(b, maxDecimal)) / multiplier
return precision !== undefined ? round(result, precision) : result
}
/**
* 精确乘法
* @param {number} a - 第一个数
* @param {number} b - 第二个数
* @param {number} [precision] - 精度(保留小数位数)
* @returns {number} 计算结果
*/
export function multiply(a, b, precision) {
const aDecimal = getDecimalPlaces(a)
const bDecimal = getDecimalPlaces(b)
const totalDecimal = aDecimal + bDecimal
const aInt = toInteger(a, aDecimal)
const bInt = toInteger(b, bDecimal)
const result = (aInt * bInt) / Math.pow(10, totalDecimal)
return precision !== undefined ? round(result, precision) : result
}
/**
* 精确除法
* @param {number} a - 被除数
* @param {number} b - 除数
* @param {number} [precision] - 精度(保留小数位数)
* @returns {number} 计算结果
*/
export function divide(a, b, precision) {
if (b === 0) {
throw new Error('除数不能为零')
}
const aDecimal = getDecimalPlaces(a)
const bDecimal = getDecimalPlaces(b)
const maxDecimal = Math.max(aDecimal, bDecimal)
// 将被除数和除数都转换为整数
const aInt = toInteger(a, maxDecimal)
const bInt = toInteger(b, maxDecimal)
// 增加精度,避免除不尽的情况
const extraPrecision = precision !== undefined ? precision : 8
const result = (aInt / bInt) * Math.pow(10, maxDecimal - maxDecimal)
return precision !== undefined ? round(result, precision) : result
}
/**
* 四舍五入
* @param {number} num - 数字
* @param {number} precision - 小数位数
* @returns {number} 四舍五入后的值
*/
export function round(num, precision) {
const multiplier = Math.pow(10, precision)
return Math.round(num * multiplier) / multiplier
}
2. 增强版本工具函数
javascript
复制代码
// utils/advancedPrecisionCalculator.js
import { add, subtract, multiply, divide, round } from './precisionCalculator'
/**
* 高级精度计算工具
*/
export const precisionCalculator = {
/**
* 多个数字相加
* @param {...number} numbers - 要相加的数字
* @param {number} [precision] - 精度
* @returns {number} 总和
*/
sum(numbers, precision) {
if (!Array.isArray(numbers)) {
numbers = Array.from(arguments)
precision = numbers[numbers.length - 1]
if (typeof precision === 'number') {
numbers = numbers.slice(0, -1)
} else {
precision = undefined
}
}
return numbers.reduce((acc, curr) => add(acc, curr), precision !== undefined ? round(0, precision) : 0)
},
/**
* 多个数字相乘
* @param {...number} numbers - 要相乘的数字
* @param {number} [precision] - 精度
* @returns {number} 乘积
*/
product(numbers, precision) {
if (!Array.isArray(numbers)) {
numbers = Array.from(arguments)
precision = numbers[numbers.length - 1]
if (typeof precision === 'number') {
numbers = numbers.slice(0, -1)
} else {
precision = undefined
}
}
return numbers.reduce((acc, curr) => multiply(acc, curr), precision !== undefined ? round(1, precision) : 1)
},
/**
* 计算平均值
* @param {...number} numbers - 数字
* @param {number} [precision] - 精度
* @returns {number} 平均值
*/
average(numbers, precision) {
if (!Array.isArray(numbers)) {
numbers = Array.from(arguments)
precision = numbers[numbers.length - 1]
if (typeof precision === 'number') {
numbers = numbers.slice(0, -1)
} else {
precision = undefined
}
}
const sum = this.sum(numbers)
const avg = divide(sum, numbers.length)
return precision !== undefined ? round(avg, precision) : avg
},
/**
* 链式计算器
*/
createCalculator(initialValue = 0) {
let value = initialValue
return {
add(num) {
value = add(value, num)
return this
},
subtract(num) {
value = subtract(value, num)
return this
},
multiply(num) {
value = multiply(value, num)
return this
},
divide(num) {
value = divide(value, num)
return this
},
round(precision) {
value = round(value, precision)
return this
},
value() {
return value
},
toNumber() {
return value
}
}
},
/**
* 比较两个数字是否相等(考虑精度误差)
* @param {number} a - 第一个数字
* @param {number} b - 第二个数字
* @param {number} tolerance - 容差
* @returns {boolean} 是否相等
*/
isEqual(a, b, tolerance = 1e-10) {
return Math.abs(subtract(a, b)) < tolerance
},
/**
* 格式化数字为字符串,避免科学计数法
* @param {number} num - 数字
* @param {number} precision - 小数位数
* @returns {string} 格式化后的字符串
*/
format(num, precision) {
const value = precision !== undefined ? round(num, precision) : num
return value.toString()
}
}
// 导出基础函数
export { add, subtract, multiply, divide, round }
在组件中使用
scss
复制代码
const {
add,
subtract,
multiply,
divide,
sum,
product,
average,
createCalculator
} = usePrecisionCalculator()
// 基础计算
const baseA = ref(0.1)
const baseB = ref(0.2)
const baseOperation = ref('add')
const basePrecision = ref(2)
const normalBaseResult = computed(() => {
const a = baseA.value
const b = baseB.value
switch (baseOperation.value) {
case 'add': return a + b
case 'subtract': return a - b
case 'multiply': return a * b
case 'divide': return a / b
default: return 0
}
})
const preciseBaseResult = computed(() => {
const a = baseA.value
const b = baseB.value
const precision = basePrecision.value
let result
switch (baseOperation.value) {
case 'add': result = add(a, b); break
case 'subtract': result = subtract(a, b); break
case 'multiply': result = multiply(a, b); break
case 'divide': result = divide(a, b); break
default: result = 0
}
return precision !== undefined ? round(result, precision) : result
})
const showBaseError = computed(() => {
return Math.abs(normalBaseResult.value - preciseBaseResult.value) > 1e-10
})
// 多个数字计算
const numberList = ref('0.1, 0.2, 0.3')
const multiPrecision = ref(2)
const numberArray = computed(() => {
return numberList.value.split(',')
.map(num => num.trim())
.filter(num => num !== '')
.map(Number)
})
const sumResult = computed(() =>
sum(numberArray.value, multiPrecision.value)
)
const productResult = computed(() =>
product(numberArray.value, multiPrecision.value)
)
const averageResult = computed(() =>
average(numberArray.value, multiPrecision.value)
)
// 链式计算
const chainResult = computed(() =>
createCalculator(10)
.add(0.1)
.multiply(2)
.subtract(0.2)
.divide(3)
.round(4)
.value()
)
// 精度测试
const test1 = computed(() => add(0.1, 0.2))
const test2 = computed(() => subtract(0.3, 0.1))
const test3 = computed(() => multiply(0.1, 0.2))
const test4 = computed(() => divide(0.3, 0.1))