简体   繁体   English

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

[英]Is C# Decimal Rounding Inconsistent?

I've been fighting decimal precision in C# coming from a SQL Decimal (38,30) and I've finally made it all the way to a rounding oddity. 我一直在使用来自SQL Decimal(38,30)的C#中的十进制精度,我终于完成了一个舍入奇怪的方法。 I know I'm probably overlooking the obvious here, but I need a little insight. 我知道我可能会忽视这里显而易见的事情,但我需要一点见解。

The problem I'm having is that C# doesn't produce what I would consider to be consistent output. 我遇到的问题是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));

Yields 产量

0.38751876912
0.38751876913
False

Uhh, 0.38751876913? 嗯,0.38751876913? Really? 真? What am I missing here? 我在这里错过了什么?

From MSDN : 来自MSDN

If the digit in the decimals position is odd, it is changed to an even digit. 如果小数位的数字是奇数,则将其更改为偶数。 Otherwise, it is left unchanged. 否则,它保持不变。

Why am I seeing inconsistent results? 为什么我看到不一致的结果? The additional precision isn't changing the 'digit in the decimals position'... 额外的精度不会改变'小数位数'......

From MSDN: 来自MSDN:

If there is a single non-zero digit in d to the right of the decimals decimal position and its value is 5 , the digit in the decimals position is rounded up if it is odd, or left unchanged if it is even . 如果decimals右边d有一个非零数字 且其值为5 ,则小数位的数字如果是奇数则向上舍入,如果是偶数则保持不变 If d has fewer fractional digits than decimals , d is returned unchanged. 如果d的小数位数小于decimals ,则返回d不变。

In your first case 在你的第一个案例

decimal a = 0.387518769125m;
Console.WriteLine(Math.Round(a, 11));

there is a single digit to the right of the 11th place, and that number is 5 . 第11位右边一位数字该数字为5 Therefore, since position 11 is even, it is left unchanged . 因此, 由于位置11是偶数,所以它保持不变 Thus, you get 因此,你得到

0.38751876912

In your second case 在你的第二个案件

decimal b = 0.3875187691250002636113061835m;
Console.WriteLine(Math.Round(b, 11));

there is not a single digit to the right of the 11th place. 第11位右边没有一位数字 Therefore, this is straight up grade-school rounding; 因此,这是直接的小学 - 学校四舍五入; you round up if the next digit is greater than 4, otherwise you round down. 如果下一个数字大于4,则向上舍入,否则向下舍入。 Since the digit to the right of the 11th place is more than 4 (it's a 5), we round up so you see 由于第11位右边的数字超过4(它是5),我们会向上看,所以你看

0.38751876913

Why am I seeing inconsistent results? 为什么我看到不一致的结果?

You're not. 你不是。 The results are completely consistent with the documentation. 结果与文档完全一致。

From MSDN - Math.Round Method (Decimal, Int32) : 从MSDN - Math.Round方法(十进制,Int32)

If there is a single non-zero digit in d to the right of the decimals decimal position and its value is 5, the digit in the decimals position is rounded up if it is odd, or left unchanged if it is even. 如果在十进制小数位右边的d中有一个非零数字且其值为5,则小数位的数字如果是奇数则向上舍入,如果是偶数则保持不变。 If d has fewer fractional digits than decimals, d is returned unchanged. 如果d的小数位数小于小数位数,则返回d不变。

The behavior of this method follows IEEE Standard 754, section 4. This kind of rounding is sometimes called rounding to nearest, or banker's rounding. 此方法的行为遵循IEEE标准754第4节。这种舍入有时称为舍入到最近,或者是银行家的舍入。 It minimizes rounding errors that result from consistently rounding a midpoint value in a single direction. 它最大限度地减少了在单个方向上始终舍入中点值所导致的舍入误差。

Note the use of single non-zero digit . 注意使用单个非零数字 This corresponds to your first examples, but not the second. 这对应于您的第一个示例,但不是第二个示例。

And: 和:

To control the type of rounding used by the Round(Decimal, Int32) method, call the Decimal.Round(Decimal, Int32, MidpointRounding) overload. 若要控制Round(Decimal,Int32)方法使用的舍入类型,请调用Decimal.Round(Decimal,Int32,MidpointRounding)重载。

The part "single non-zero digit in d to the right of the decimals decimal position and its value is 5" explains the result. “小数位小数点右侧d中的单个非零数字及其值为5”部分解释了结果。 Only when the part to round is exactly 0,5 the rounding rule comes into play. 只有当圆形部分正好为0.5时,才能使用舍入规则。

Let's shift both numbers over 11 digits to the left: 让我们将两个数字都移到左边11位数:

38751876912.5 38751876912.5
38751876912.50002636113061835 38751876912.50002636113061835

Using banker's rounding, we round the first one down. 使用银行家的四舍五入,我们将第一个四舍五入。 Under every midpoint-rounding system, we round the second number up (because it is not at the midpoint) . 每个中点舍入系统下,我们将第二个数字向上舍入(因为它不在中点)

.Net is doing exactly what we'd expect it to. .Net正在做我们期望的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM