在 JavaScript 中获得准确的百分比计算

Get accurate percentage calculation in JavaScript

我有一个函数可以计算交易费用的百分比。为了测试它,我编写了下面的函数以确保速率计算准确无误。但是,计算出的速率 (1 - part/whole) * 100 与传递给函数的实际速率存在微小差异。

有没有办法更正错误并确保rate === calculated rate

P.S:四舍五入到固定的小数位数并不能解决问题,因为汇率的小数位数可以变化。

const getAmount = (amount, rate) => {
    const fee = amount * (rate / 100);
    const amountAfterFee = amount - fee;
    const calculatedRate = (1 - amountAfterFee / amount) * 100;
    return { amount, fee, amountAfterFee, rate, calculatedRate };
};

console.log(getAmount(3000, 5)); 
// { amount: 3000, fee: 150, amountAfterFee: 2850, rate: 5, calculatedRate: 5.000000000000004 }

console.log(getAmount(3000, 6.0)); 
// { amount: 3000, fee: 180, amountAfterFee: 2820, rate: 6, calculatedRate: 6.000000000000005 }

console.log(getAmount(3000, 7.3)); 
// { amount: 3000, fee: 219, amountAfterFee: 2781, rate: 7.3, calculatedRate: 7.299999999999995 }

console.log(getAmount(3000, 8.12345)); 
// { amount: 3000, fee: 243.7035, amountAfterFee: 2756.2965, rate: 8.12345, calculatedRate: 8.123449999999998 }

您正在使用浮点数进行计算。由于 their internal representation,可能存在精度问题,例如您所面对的问题。有关详细信息,请参阅 link。

总而言之,由于您似乎正在处理货币计算,因此最好的选择是使用特定的数据类型而不是浮点数,例如 currency.js:

const m = (amount) => currency(amount, { precision: 10 })
const getAmount = (amount, rate) => {
    const fee = m(amount).multiply(m(rate).divide(100));
    const amountAfterFee = m(amount).subtract(fee);
    const calculatedRate = m(1).subtract(amountAfterFee.divide(amount)).multiply(100);
    return { amount, fee, amountAfterFee, rate, calculatedRate };
};

console.log(getAmount(3000, "5")); 
// { amount: 3000, fee: 150, amountAfterFee: 2850, rate: 5, calculatedRate: 5.000000000000004 }

console.log(getAmount(3000, "6.0")); 
// { amount: 3000, fee: 180, amountAfterFee: 2820, rate: 6, calculatedRate: 6.000000000000005 }

console.log(getAmount(3000, "7.3")); 
// { amount: 3000, fee: 219, amountAfterFee: 2781, rate: 7.3, calculatedRate: 7.299999999999995 }

console.log(getAmount(3000, "8.12345")); 
// { amount: 3000, fee: 243.7035, amountAfterFee: 2756.2965, rate: 8.12345, calculatedRate: 8.123449999999998 }
<script src="https://cdn.jsdelivr.net/npm/currency.js"></script>

当然还有其他的选择,比如dinero.js。一如既往,哪一个更适合您取决于您​​的具体情况。