C# 如何防止十进制变量类型的货币舍入错误?
我正在做一个付款计划计算器。我从“double”变量类型切换到“decimal”变量类型以防止舍入错误,但我仍然在某个地方得到了一个。我提出了这个数据集来测试我的代码,因为有一个明确的余数: 余额:1575.75美元C# 如何防止十进制变量类型的货币舍入错误?,c#,decimal,rounding-error,C#,Decimal,Rounding Error,我正在做一个付款计划计算器。我从“double”变量类型切换到“decimal”变量类型以防止舍入错误,但我仍然在某个地方得到了一个。我提出了这个数据集来测试我的代码,因为有一个明确的余数: 余额:1575.75美元 首期付款:500.00美元 剩余余额:1075.75美元 首期付款后的付款数量:9 分期付款金额:$119.53(x8) 其余:119.51美元 我将数据类型从double切换到decimal(显然) 我尝试过多次重新编写代码,以不同的方式计算相同的内容(这就是为什么此时的一些数学
首期付款:500.00美元
剩余余额:1075.75美元
首期付款后的付款数量:9
分期付款金额:$119.53(x8)
其余:119.51美元 我将数据类型从double切换到decimal(显然) 我尝试过多次重新编写代码,以不同的方式计算相同的内容(这就是为什么此时的一些数学不是“极简主义”的原因) 我试着让我的代码更模块化,以找出舍入误差
// Method within my WinForms project
public void CalculateInstallmentPayments()
{
decimal currentBalance = Convert.ToDecimal(txtBalanceInput.Text); // Current Balance
decimal downPayment = Convert.ToDecimal(txtDownPayment.Text); // Down Payment
decimal installmentCount = sliderRemainingPmtCount.Value; // Installment Count
decimal balanceAfterDP = currentBalance - downPayment; // Balance After Down Payment
decimal installmentAmount = (balanceAfterDP / installmentCount); // Installment Amount
decimal remainderPayment = (balanceAfterDP - (installmentAmount * (installmentCount - 1))); // Final Payment (Remainder)
// Using Rich Text box as a 'Console' for debugging
rtxtNotate.Text = ($"Current Balance: {currentBalance.ToString()}\nDown Payment: {downPayment.ToString("C")}\n" +
$"Installment Count: {installmentCount.ToString()}\nInstallment Amount: {installmentAmount.ToString("C")}\n" +
$"Remainder: {remainderPayment.ToString("C")}\n");
}
这是当前的输出:
当前余额:1575.75首期付款:500.00美元
分期付款计数:9
分期付款金额:119.53美元
剩余部分:$119.53——这是舍入误差。应该是119.51美元
我已经重构这段代码好几个小时了,我觉得我遗漏了一些非常简单的东西。在应用它之前,你没有把首付金额四舍五入。因此,您得到的结果是正确的,没有(或非常小的)舍入误差。。。对于支付约119.52777美元的人
如果先对分期付款金额进行四舍五入,然后再将其存储在installmentAmount变量中,则可能会得到所需的答案。十进制数据类型不是两位小数的定点类型,而是以十位小数为基数的浮动点 您可以使用它来防止在将精确表示为以十为基数的数字转换为以二为基数的数字(如0.1)时出现某些特定形式的舍入错误 但是
1075.75/9=119.5277777
这不是一个以10为基数或以2为基数精确表示的数字,因此即使使用十进制
,您也会得到一些(非常小的)舍入误差
但这实际上不是你的问题。您可以使用toString(“c”)
手动将数字四舍五入。在输出中四舍五入到2位数,但计算在背景中仍然使用更多的位数
因此,剩余部分和分期付款都是119.52777
,并且全部加起来。当你把它四舍五入到两位数之后,看起来你少了几美分。如果要使用舍入分期计算余数,您必须自己使用Math.round()
更新分期金额计算,如下所示
decimal installmentAmount = Math.Round((balanceAfterDP / installmentCount),2);
您可以使用:
decimal currentBalance = 1575.75M; // Current Balance
decimal downPayment = 500.00M; // Down Payment
decimal installmentCount = 9; // Installment Count
decimal balanceAfterDP = currentBalance - downPayment; // Balance After Down Payment
decimal installmentAmount = Math.Round((balanceAfterDP / installmentCount),2, MidpointRounding.AwayFromZero); // Installment Amount
decimal remainderPayment = (balanceAfterDP - (installmentAmount * (installmentCount - 1))); // Final Payment (Remainder)
您将得到正确的值:119.51这是使用Math.Round()的少数几个好理由之一,您需要将分期付款计算为实际可以支付的金额。精确到一便士,不用了。谢谢。我在上面看到了,这是正确的答案,但是按照你的方式编排格式是非常有帮助的。非常感谢。