C#十进制舍入不一致吗?

我一直在争取来自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 :

如果小数位中的数字是奇数,则将其更改为偶数位。 否则,保持不变。

为什么我看到不一致的结果? 额外的精度不会改变“小数位数位”…

来自MSDN:

如果小数点右侧 decimals 右边有一个非零数字, 其值为5 ,则小数点位数如果是奇数,则向上舍入,如果是偶数则保持不变 。 如果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)); 

第十一名的右侧没有一位数字 。 因此,这是小学四舍五入, 如果下一个数字大于4,则向上取整,否则向下取整。 由于第11位右边的数字超过4(这是5),所以我们收起来让你看

 0.38751876913 

为什么我看到不一致的结果?

你不是。 结果与文档完全一致。

从MSDN – Math.Round方法(十进制,Int32) :

如果小数点右侧小数点右边有一个非零数字,其值为5,则小数点位数如果是奇数,则向上舍入,如果是偶数则保持不变。 如果d的小数位数小于小数位,则d不变。

这种方法的行为遵循IEEE标准754第4节。这种四舍五入有时被称为四舍五入到四舍五入或四舍五入。 它可以减less由于在一个方向上不断舍入中点值而导致的舍入误差。

请注意使用单个非零数字 。 这相当于你的第一个例子,但不是第二个例子。

和:

要控制Round(Decimal,Int32)方法所使用的舍入types,请调用Decimal.Round(Decimal,Int32,MidpointRounding)重载。

“小数点右侧小数点右边的单个非零位,其值为5”的部分解释了结果。 只有当轮的部分恰好为0,5时,舍入规则才会起作用。

让我们把这两个数字左移11位:

38751876912.5
38751876912.50002636113061835

用银行家的四舍五入,我们把第一个下来。 在每个中点取整系统下,我们围绕第二个数字(因为它不在中点)

.Net正在做我们期望的。