我一直在使用来自SQL Decimal(38,30)的C#中的十进制精度,我终于完成了一个舍入奇怪的方法。我知道我可能会忽视这里显而易见的事情,但我需要一点见解。
我遇到的问题是C#没有产生我认为是一致输出的东西。
decimal a = 0.387518769125m;
decimal b = 0.3875187691250002636113061835m;
Console.WriteLine(Math.Round(a, 11));
Console.WriteLine(Math.Round(b, 11));
Console.WriteLine(Math.Round(a, 11) == Math.Round(b, 11));
产量
0.38751876912
0.38751876913
False
嗯,0.38751876913?真?我在这里缺少什么?
来自MSDN:
如果小数位的数字是奇数,则将其更改为偶数。否则,它保持不变。
为什么我看到不一致的结果?额外的精度不会改变'小数位数'......
答案 0 :(得分:44)
来自MSDN:
如果
d
小数位置的decimals
右侧中有一个非零数字且其值为5
< / strong>,小数位的数字如果是奇数则向上舍入,如果是偶数则保持不变。如果d
的小数位数少于decimals
,则d
将保持不变。
在你的第一个案例中
decimal a = 0.387518769125m;
Console.WriteLine(Math.Round(a, 11));
是第11位的右侧的单个数字,,该数字为5
。因此,因为位置11是偶数,所以保持不变。因此,你得到了
0.38751876912
在你的第二个案例中
decimal b = 0.3875187691250002636113061835m;
Console.WriteLine(Math.Round(b, 11));
不是第11位的右侧的单个数字。因此,这是直接的小学 - 学校四舍五入;如果下一个数字大于4,则向上舍入,否则向下舍入。由于第11位右侧的数字超过4(它是5),我们将向上舍入,以便您看到
0.38751876913
为什么我看到不一致的结果?
你不是。结果与文档完全一致。
答案 1 :(得分:26)
来自MSDN - Math.Round Method (Decimal, Int32):
如果小数位小数点右边的d中有一个非零数字且其值为5,则小数位的数字如果是奇数则向上舍入,如果是偶数则保持不变。如果d的小数位数小于小数位数,则d保持不变。
此方法的行为遵循IEEE标准754第4节。这种舍入有时称为舍入到最近,或者是银行家的舍入。它最大限度地减少了在单一方向上始终舍入中点值所导致的舍入误差。
请注意使用单个非零数字。这与您的第一个示例相对应,但不是第二个。
和
要控制Round(Decimal,Int32)方法使用的舍入类型,请调用Decimal.Round(Decimal,Int32,MidpointRounding)重载。
答案 2 :(得分:4)
“小数位小数点右侧d中的单个非零数字及其值为5”解释了结果。只有当圆形部分正好为0.5时,才能使用舍入规则。
答案 3 :(得分:4)
让我们将这两个数字移到左边的11位数字上:
38751876912.5
38751876912.50002636113061835
使用银行家的舍入,我们将第一个四舍五入。在每个中点舍入系统下,我们将第二个数字向上舍入(因为它不在中点)。
.Net正在做我们期望的事情。