如何使用十进制变量类型防止货币舍入错误?

时间:2019-05-27 22:00:29

标签: c# decimal rounding-error

我正在使用付款计划计算器。我从“双精度”变量类型切换为“十进制”变量类型,以防止舍入错误,但我仍然在某个地方遇到问题。我想出了这个数据集来测试我的代码,因为有明显的余量:

余额:$ 1,575.75
首付款:$ 500.00
剩余余额:1,075.75美元
预付款后的付款次数:9
分期付款金额:$ 119.53(x8)
剩余部分:$ 119.51

我将数据类型从双精度切换为十进制(很明显) 我尝试多次重写代码,以不同的方式计算相同的内容(这就是为什么此时的某些数学运算小于“极简主义者”的原因) 我尝试使代码更具模块化,以发现舍入错误

// 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

我已经将这些代码重构了几个小时,感觉好像缺少了一个非常简单的东西。

4 个答案:

答案 0 :(得分:1)

在应用预付款金额之前,您不需要四舍五入。因此,您将获得正确的结果,而没有(或非常小的)舍入错误……对于付款金额约为119.52777777777美元的人来说

如果在将分期付款金额存储到installmentAmount变量中之前四舍五入,您可能会得到所需的答案。

答案 1 :(得分:1)

<div style={{ display: "flex" }}> <div style={{ flex: 1, backgroundColor: "lightGrey", wordBreak: "break-word" }} > A really, really, really, really long phrase here that will fit this div, and may wrap onto multiple lines if necessary. In this case it should fill half of the available space as the other div will cover the other half of the space. </div> <div style={{ flex: 1, backgroundColor: "lightBlue" }}> Some other text </div> </div> 数据类型不是具有两位小数的定点类型,而是以10为底的浮点数。

您可以使用它来防止将以10为底的精确表示的decimal转换为以2为底的number时发生的某些特定形式的舍入错误。

但是1075.75 / 9 = 119.5277777 ...

这不是number,不能以10为底数或以2为底数精确表示,因此即使使用decimal,也会出现一些(非常小的)舍入误差。

但这实际上不是您的问题。您用toString("c")手动舍入数字。您在输出中四舍五入到两位数,但是计算仍然在后台使用更多位数。

因此,余数和分期付款为119.52777777777,所有这些加起来。之后,将其四舍五入到两位数时,就好像您丢失了美分。如果要使用四舍五入的分期付款计算余数,则必须使用Math.Round()

将其四舍五入

答案 2 :(得分:0)

更新如下的分期付款金额计算

decimal installmentAmount = Math.Round((balanceAfterDP / installmentCount),2);

答案 3 :(得分:0)

您可以使用:

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