如何计算Reprofiled Amount列最后一笔付款,使总额匹配RC金额并修正精度误差
解决最后一笔付款金额差额问题,确保总额与RC一致
问题背景
需要计算Reprofiled Amount列的最后一笔付款(保留两位小数),使所有付款总额与Research Costs(RC)金额完全相等,差额需加到最后一笔季度付款中。
目前将3个付款值存储在numAmounts数组:
const numAmounts = [ 106017.96, 106017.96, 106017.96 ];
当前代码计算出的最后一笔付款为106017.96999999997,经formatAsCurrency(remainningAmount, 2, 2)格式化后变为106017.96,导致所有付款总和比RC金额少1分钱,需将这1分钱补到最后一笔付款中。
原代码片段:
function formatAsCurrency(numValue, numMinimumDigits, numMaximumDigits) { try { if (!numMinimumDigits || isNaN(numMinimumDigits)) { numMinimumDigits = 0; } numValue = Number(numValue.toString().replace(/[^0-9.-]/g, "")); if (!isNaN(numValue)) { if (!numMinimumDigits || numMinimumDigits <= 0) { return Number(numValue.toFixed(0)).toString(); } else { return numValue.toLocaleString("en-US", { minimumFractionDigits: numMinimumDigits, maximumFractionDigits: numMaximumDigits }); } } else { return numValue; } } catch (ex) { alert("Error in formatAsCurrency(): " + ex.toString()); disableAll(); return false; } } const RC = 424071.85; const numAmounts = [ 106017.96, 106017.96, 106017.96 ]; const sum = numAmounts.reduce((acc, curr) => acc + curr, 0); const remainningAmount = RC - sum; console.log("remainningAmount", formatAsCurrency(remainningAmount, 2, 2));
解决方案
问题源于浮点数精度误差及格式化时的截断。需先计算精确差额,再调整最后一笔付款,确保总额完全匹配RC。
修改后的代码:
function formatAsCurrency(numValue, numMinimumDigits, numMaximumDigits) { try { if (!numMinimumDigits || isNaN(numMinimumDigits)) { numMinimumDigits = 0; } numValue = Number(numValue.toString().replace(/[^0-9.-]/g, "")); if (!isNaN(numValue)) { if (!numMinimumDigits || numMinimumDigits <= 0) { return Number(numValue.toFixed(0)).toString(); } else { return numValue.toLocaleString("en-US", { minimumFractionDigits: numMinimumDigits, maximumFractionDigits: numMaximumDigits }); } } else { return numValue; } } catch (ex) { alert("Error in formatAsCurrency(): " + ex.toString()); disableAll(); return false; } } const RC = 424071.85; const numAmounts = [ 106017.96, 106017.96, 106017.96 ]; // 计算当前总和并保留两位小数,消除浮点数累加误差 const sum = Number(numAmounts.reduce((acc, curr) => acc + curr, 0).toFixed(2)); // 计算RC与当前总和的精确差额 const diff = RC - sum; // 调整最后一笔付款,保留两位小数确保精度 const adjustedLastAmount = Number((numAmounts[numAmounts.length - 1] + diff).toFixed(2)); // 更新付款数组 const adjustedAmounts = [...numAmounts.slice(0, -1), adjustedLastAmount]; // 验证调整后的总额 const total = adjustedAmounts.reduce((acc, curr) => acc + curr, 0); console.log("调整后的付款数组:", adjustedAmounts.map(amt => formatAsCurrency(amt, 2, 2))); console.log("验证总额:", formatAsCurrency(total, 2, 2)); // 输出应等于RC的424071.85
关键说明
- 先将总和转为两位小数,避免浮点数累加带来的精度偏差
- 计算RC与当前总和的精确差额,该差额即为需要补充到最后一笔的金额
- 调整最后一笔付款后,再次转为两位小数,确保金额格式符合要求
- 验证调整后的总额,确保与RC完全一致
内容的提问来源于stack exchange,提问作者Karim Ali
相关产品推荐
相关产品推荐

