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

Tug*_*ain 5 c# sql-server currency

是否有最佳实践可以在.Net中使用舍入算法进行十进制货币舍入操作,并将后端系统考虑在内?真实的世界体验赞赏.


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

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

以下是.Net默认的Banker舍入到小数点后两位的示例,而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
Run Code Online (Sandbox Code Playgroud)

如果我从SQL Server中检索一个值并让它处理四舍五入的话,我会在这里和那里找到便士,因为.Net告诉我,因为它是默认的Banker's Rounding.

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


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

Nig*_*888 5

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

除银行业务外,计算运费,所得税和营业税始终使用“从零开始”舍入。

我可以想到的现实世界中,对银行家四舍五入的唯一用途是用于计算利息,平分差额或支付佣金。

Microsoft没有选择将默认值设置MidpointRounding.ToEven为有充分的理由。他们这样做是为了保持与Visual Basic(.NET之前)的向后兼容性。这样做不是因为它是合理的默认值,还是任何形式的最佳默认值。如果他们今天必须再次做出决定,那很可能是MidpointRounding.AwayFromZero

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