一、1. 生产环境推荐使用 decimal.js - 功能完整,性能良好
使用第三方数学计算库( decimal.js)
npm install decimal.js
封装计算方法
import Decimal from "decimal.js-light"
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
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直接使用
<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 = () => {
const a = new Decimal(num1.value)
const b = new Decimal(num2.value)
result.value = a.plus(b).toNumber()
}
</script>
二、使用big.js
npm install big.js
import Big from 'big.js'
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
}
}
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
}
}
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
}
}
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
}
}
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. 基础版本工具函数
function getDecimalPlaces(num) {
const numStr = num.toString()
const decimalIndex = numStr.indexOf('.')
return decimalIndex === -1 ? 0 : numStr.length - decimalIndex - 1
}
function getMaxDecimalPlaces(...numbers) {
return Math.max(...numbers.map(num => getDecimalPlaces(num)))
}
function toInteger(num, decimalPlaces) {
return Math.round(num * Math.pow(10, decimalPlaces))
}
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
}
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
}
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
}
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
}
export function round(num, precision) {
const multiplier = Math.pow(10, precision)
return Math.round(num * multiplier) / multiplier
}
2. 增强版本工具函数
import { add, subtract, multiply, divide, round } from './precisionCalculator'
export const precisionCalculator = {
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)
},
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)
},
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
}
}
},
isEqual(a, b, tolerance = 1e-10) {
return Math.abs(subtract(a, b)) < tolerance
},
format(num, precision) {
const value = precision !== undefined ? round(num, precision) : num
return value.toString()
}
}
export { add, subtract, multiply, divide, round }
在组件中使用
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))