在 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。一如既往,哪一个更适合您取决于您的具体情况。
我有一个函数可以计算交易费用的百分比。为了测试它,我编写了下面的函数以确保速率计算准确无误。但是,计算出的速率 (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。一如既往,哪一个更适合您取决于您的具体情况。