是否有最佳实践,考虑到后端系统,在.Net中使用哪种舍入算法进行十进制货币舍入运算?真实世界的经验表示赞赏。
.Net默认情况下使用Banker's Rounding。(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
如果我曾经从SQL Server中检索一个值并让它处理舍入,那么与.Net告诉我的内容相比,我会四处走动,因为这是默认的Banker's Rounding。
似乎我应该更进一步,在整个.Net代码库中使用算术舍入法,但是我看到一个使用默认银行家舍入法的开源项目(nopCommerce),这使我想知道最好的方法是什么。
也许更好的问题是:是否有理由不对.Net中的货币使用算术舍入(MidpointRounding.AwayFromZero)?
银行家的四舍五入在现实世界中很少有意义。我曾经在银行业工作过,他们曾经派我执行任务,以消除由于这一罪魁祸首而导致的报告中的“四舍五入错误”。
除银行业务外,计算运费,所得税和营业税始终使用“从零开始”舍入。
我可以想到的现实世界中对银行家四舍五入的唯一用途是用于计算利息和分割差额或支付佣金。
Microsoft没有选择将默认值设置MidpointRounding.ToEven
为有充分的理由。他们这样做是为了保持与Visual Basic(.NET之前)的向后兼容性。这样做不是因为它是合理的默认值,还是任何形式的最佳默认值。如果他们今天必须再次做出决定,那很可能是MidpointRounding.AwayFromZero
。
请记住,当有人检查您的工作时,他们将使用我们都在小学学习的“远离零”的方法。我认为,“因为微软将其设置为默认值”不足以使程序使用它。如果有必要,在使用银行四舍五入时应该有一个有效的商业理由。如果未在应用程序需求中明确调用它,则应使用MidpointRounding.AwayFromZero
。最好将应用程序框架中的默认值更改为MidpointRounding.AwayFromZero
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句