c# - 在 .Net 中使用哪种货币舍入算法?

标签 c# sql-server currency

是否有关于在 .Net 中使用哪种舍入算法进行十进制货币舍入操作并考虑后端系统的最佳实践?真实世界的经验表示赞赏。


.Net 默认使用 Banker’s Rounding。 (MidpointRounding.ToEven) 这与我将使用的 SQL Server 后端不一致,因为 SQL Server 使用算术舍入 (MidpointRounding.AwayFromZero) 并且没有模仿银行家四舍五入的内置函数。

注意:我在 SQL Server 中使用 decimal(18, 4),在 .Net 中使用 decimal

下面是 .Net 的默认银行家四舍五入到两位小数与 SQL Server 的四舍五入到两位小数的示例:

| Value | .Net  | SQL Server  |
|-------|-------|-------------|
| 2.445 | 2.44  | 2.45        |
| 2.455 | 2.46  | 2.46        |
| 2.465 | 2.46  | 2.47        |
| 3.445 | 3.44  | 3.45        |
| 3.455 | 3.46  | 3.46        |
| 3.465 | 3.46  | 3.47        |

// t-sql
declare @decimalPlaces int
set @decimalPlaces = 2

select round(convert(decimal(18, 4), 2.445), @decimalPlaces) -- 2.45
select round(convert(decimal(18, 4), 2.455), @decimalPlaces) -- 2.46
select round(convert(decimal(18, 4), 2.465), @decimalPlaces) -- 2.47
select round(convert(decimal(18, 4), 3.445), @decimalPlaces) -- 3.45
select round(convert(decimal(18, 4), 3.455), @decimalPlaces) -- 3.46
select round(convert(decimal(18, 4), 3.465), @decimalPlaces) -- 3.47

// .Net
var algorithm = MidpointRounding.ToEven;
var decimalPlaces = 2;
Console.WriteLine(decimal.Round(2.445M, decimalPlaces, algorithm).ToString()); // 2.44
Console.WriteLine(decimal.Round(2.455M, decimalPlaces, algorithm).ToString()); // 2.46
Console.WriteLine(decimal.Round(2.465M, decimalPlaces, algorithm).ToString()); // 2.46
Console.WriteLine(decimal.Round(3.445M, decimalPlaces, algorithm).ToString()); // 3.44
Console.WriteLine(decimal.Round(3.455M, decimalPlaces, algorithm).ToString()); // 3.46
Console.WriteLine(decimal.Round(3.465M, decimalPlaces, algorithm).ToString()); // 3.46

如果我从 SQL Server 检索一个值并让它处理舍入,与 .Net 告诉我的相比,我会在这里和那里少花钱,因为它是默认的银行家舍入。

似乎我应该继续前进并在我的 .Net 代码库中使用算术舍入,但我看到一个开源项目 ( nopCommerce ) 使用默认的银行家舍入,所以我想知道什么是最好的方法。


也许更好的问题是:是否有任何理由对 .Net 中的货币使用算术舍入 (MidpointRounding.AwayFromZero)?

最佳答案

来自 the documentation :

Rounding away from zero is the most widely known form of rounding, while rounding to nearest even is the standard in financial and statistical operations. It conforms to IEEE Standard 754, section 4. When used in multiple rounding operations, rounding to nearest even reduces the rounding error that is caused by consistently rounding midpoint values in a single direction. In some cases, this rounding error can be significant.

银行家的舍入很少在现实世界中有意义。我曾经在银行业工作,他们曾经派我去执行一项任务,以消除由于这个罪魁祸首导致的报告中的“舍入错误”。

除了银行业务,计算运费、所得税和销售税始终使用“远离零”舍入。

我能想到的银行家四舍五入在现实世界中的唯一用途可能是计算利息和拆分差额或支付佣金。

Microsoft 没有选择使用默认的 MidpointRounding.ToEven 是有充分理由的。他们这样做是为了保持与 Visual Basic(.NET 之前)的向后兼容性。之所以没有这样做,是因为它是一个合理的默认值,或者是任何类型的最佳默认值。如果他们今天必须再次做出决定,那很可能是 MidpointRounding.AwayFromZero

请记住,当有人检查您的作业时,他们将使用我们在小学时都学到的“远离零”方法。在我看来,“因为 Microsoft 将其设置为默认值”并不足以成为该程序使用它的借口。如果有必要,应该有正当的商业理由使用银行四舍五入。如果应用需求中没有明确调用,则应使用MidpointRounding.AwayFromZero。最好将应用程序框架中的默认值更改MidpointRounding.AwayFromZero

关于c# - 在 .Net 中使用哪种货币舍入算法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29185850/

相关文章:

sql-server - 如何在 SQL Server 中使用 alter 设置列的默认值?

c# - 谷歌货币转换器

java - 如何在mysql表中保存货币符号unicode

java - 给定货币代码的货币符号

c# - ASP.NET 图表控件,是否可以在饼图上使用渐变?

c# - C# 6 字符串插值的默认区域性是什么?

sql-server - 由于 newsequentialid() 功能不兼容,无法将 bacpac 文件导入到 Azure

sql-server - 找不到证书

c# - 如何使用 LINQ 从列表中获取逗号分隔的值列表?

javascript - 使用 Jquery 在 asp.net GridView 中查找所有复选框