【问题标题】:C# Decimal type rounding off inappropriatelyC# 小数类型舍入不当
【发布时间】:2015-10-07 12:37:45
【问题描述】:

我有一个内部银行解决方案,可用于我参加的夏令营。问题来了,有些账户在赛季结束时正好是一分钱。

我正在使用带有两个表的 SQL Server Express。一张包含所有帐户的表,其中包含当前余额。另一个表是正在运行的事务日志。这个想法是,如果我要总结日志中的所有交易,它应该等于任何给定帐户的当前帐户余额。

但事实并非如此。比如我对数据库求和,看到给定的账户应该有$15.10,但是账户表显示他们有$15.09的余额

以下是相关代码:

//Amount is negative, they bought something
if (amount <= 0)
{
    //Check if they have enough money to buy, or they are a paid account type (faculty, staff)

    if (account.Balance >= Math.Abs(amount) || account.AccountType > AccountType.Camper)
        account.Balance -= Math.Abs(amount);
    else
        return Error.LowBalance;
}
else
{
    account.Balance += Math.Abs(amount);
}

var t = new Transaction
{
    AccountId = account.Id,
    Amount = amount,
    SubmittedBy = username,
    TransactionRefId = refId,
    ComputerHostname = hostname,
    Location = location,
    Notes = notes
};

_db.Transactions.Add(t);
_db.SaveChanges();

我正在使用实体框架,代码优先。 Account.BalanceamountTransaction.Amount的数据类型都是System.Decimal

我不明白为什么会出现舍入错误,我在这种情况下使用了所有正确的数据类型。我看到这种情况的通常方式是当他们对$0.75 有两个不同的交易时。出于某种原因,代码说0.05 + 0.05 = 0.09

在我的数据库中,Accounts.Balance 列数据类型为 decimal(18,2)

我知道浮点数有时可以做到这一点,但我正在寻找解决办法。我以为我被 System.Decimal 数据类型覆盖了。

【问题讨论】:

  • “代码显示 0.05 + 0.05 = 0.09”是什么意思?不清楚你在哪里看到了什么。
  • 您能否使用调试器找到导致舍入错误的确切代码行?
  • 您是否尝试将类型更改为Money? msdn.microsoft.com/en-us/library/ms179882.aspx
  • @JonSkeet 就像那似乎正在发生的事情。如果我以 0.75 美元申请一笔交易,然后以 0.75 美元申请另一笔交易,系统显示余额为 1.49 美元
  • @AdamSchiavone 如果这是正确的(老实说,我怀疑它不是),那么您应该能够轻松地想出一个最小的复制器。编写一个程序,将属性设置为1.50m 并将其保存到数据库中。如果它存储1.50 以外的其他内容,则编辑您的问题以显示具有该行为的程序。如果它存储了1.50,那么问题就不是你说的那样。

标签: c# sql-server floating-point rounding-error


【解决方案1】:

您只存储了 2 个十进制数字并在其后丢弃所有内容,从而失去了过程中的精度。存储更多的十进制数字。

另一个丢失精度的例子:https://social.msdn.microsoft.com/Forums/en-US/145d2b1c-793a-4d3e-8cbf-ac9bcc6dd273/rounding-c-decimal-values-to-sql-decimal-or-numeric-fields?forum=adodotnetentityframework

【讨论】:

  • 所以我需要将decimal(18, 2) 更改为decimal(18, 4)
  • 或更多,取决于您想要的可靠性,C# 中的 Decimal 只是“具有更多位的双精度数”,但也不可信。
  • 我不相信这个答案适用。那篇文章是关于当你将一个小数点为 10 的数字保存到只有 2 个的 db 字段时截断的。它截断,而不是四舍五入。在他的情况下,数据库有空间正确存储值。
  • @AlexandreBorela decimal 不仅仅是更高的精度doubledecimal 类型将值表示为整数乘以 10 的幂(技术上始终是 10 的负幂),而不是 2 的幂。这意味着 decimal 可以精确地表示 1/5(2 * 10^- 1) double 不能。
  • msdn.microsoft.com/en-us/library/ms187746.aspx 这与建议的解决方案直接相关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多