C# Round()函数,数值四舍五入取整方式

今天在项目中偶然遇到使用decimal.Round()函数对decimal值进行取2位小数时,0.995的值为1. 代码如下:

decimal newVal = decimal.Round((decimal)0.995, 2);

运行后newVal=1. 因为是涉及到打折的问题,所以预期期望应该是0.99。于是找了下资料,读了MSDN的文档,对decimal取整的用法大致熟悉了,遂成此文,用于参考。

decimal.Round()有四个重载方法:

  • decimal.Round(decimal)
  • decimal.Round(decimal, Int32)
  • decimal.Round(decimal, Int32, MidpointRounding)
  • decimal.Round(decimal, MidpointRounding)

1. decimal.Round(decimal)

public static decimal Round(
    decimal d   
)

返回最接近d的整数,如果d在相邻的两个整数之间(及为X.5),则返回其中一个为偶数的值。如,8.5->8, 7.5->8.

代码示例如下:

using System;

public class Example
{
   public static void Main()
   {
      for (decimal value = 100m; value <= 102m; value += .1m)
         Console.WriteLine("{0} --> {1}", value, Decimal.Round(value));

   }
}
// The example displays the following output:
//     100 --> 100
//     100.1 --> 100
//     100.2 --> 100
//     100.3 --> 100
//     100.4 --> 100
//     100.5 --> 100
//     100.6 --> 101
//     100.7 --> 101
//     100.8 --> 101
//     100.9 --> 101
//     101.0 --> 101
//     101.1 --> 101
//     101.2 --> 101
//     101.3 --> 101
//     101.4 --> 101
//     101.5 --> 102
//     101.6 --> 102
//     101.7 --> 102
//     101.8 --> 102
//     101.9 --> 102
//     102.0 --> 102

2. decimal.Round(decimal, Int32)

public static decimal Round(
    decimal d,
    int decimals
)

decimals范围:[0,28]

返回精度为decimals,对d进行取整的数。实际上该函数对精度还是会使用取整操作,相当于调用Round(decimal, Int32, MidpointRounding.ToEven).当所指定精度后一位数刚好在两个数中间时,会更加该数值的奇偶性来取舍。 如当精度为2时,2.345是2.34,而2.355则是2.36.这个处理过程是被广为接受的取偶法或者银行取舍法。这种方式在最大程度上避免了四舍五入带来的偏差。

实例代码如下:

using System;

class Example
{
   public static void Main()
   {
      // Define a set of Decimal values.
      decimal[] values = { 1.45m, 1.55m, 123.456789m, 123.456789m, 
                           123.456789m, -123.456m, 
                           new Decimal(1230000000, 0, 0, true, 7 ),
                           new Decimal(1230000000, 0, 0, true, 7 ), 
                           -9999999999.9999999999m, 
                           -9999999999.9999999999m };
      // Define a set of integers to for decimals argument.
      int[] decimals = { 1, 1, 4, 6, 8, 0, 3, 11, 9, 10};

      Console.WriteLine("{0,26}{1,8}{2,26}", 
                        "Argument", "Digits", "Result" );
      Console.WriteLine("{0,26}{1,8}{2,26}", 
                        "--------", "------", "------" );
      for (int ctr = 0; ctr < values.Length; ctr++)
        Console.WriteLine("{0,26}{1,8}{2,26}", 
                          values[ctr], decimals[ctr], 
                          Decimal.Round(values[ctr], decimals[ctr]));
    }
}
// The example displays the following output:
//                   Argument  Digits                    Result
//                   --------  ------                    ------
//                       1.45       1                       1.4
//                       1.55       1                       1.6
//                 123.456789       4                  123.4568
//                 123.456789       6                123.456789
//                 123.456789       8                123.456789
//                   -123.456       0                      -123
//               -123.0000000       3                  -123.000
//               -123.0000000      11              -123.0000000
//     -9999999999.9999999999       9    -10000000000.000000000
//     -9999999999.9999999999      10    -9999999999.9999999999

3. Decimal.Round Method (Decimal, Int32, MidpointRounding)

public static decimal Round(
    decimal d,
    int decimals,
    MidpointRounding mode
)

返回指定精度的四舍五入的值,如果是中间值时,根据参数来mode来进行取舍。

前两个参数跟上两个方法无异,主要来说一下MidpointRounding结构体。

MidpointRounding结构体有两个值,用于在取整时来判断是进位还是舍值的情形:

  • AwayFromZero:远离0的取法,如4.5取一位应为5,-4.5->-5;
  • ToEven: 取偶数法,如4.5取以为为4。

具体的算法可参见以下例子:

/*
This code example produces the following results:

 3.4 = Math.Round( 3.45, 1)
-3.4 = Math.Round(-3.45, 1)

 3.4 = Math.Round( 3.45, 1, MidpointRounding.ToEven)
 3.5 = Math.Round( 3.45, 1, MidpointRounding.AwayFromZero)

-3.4 = Math.Round(-3.45, 1, MidpointRounding.ToEven)
-3.5 = Math.Round(-3.45, 1, MidpointRounding.AwayFromZero)

*/

4. Decimal.Round Method (Decimal, MidpointRounding)

public static decimal Round(
    decimal d,
    MidpointRounding mode
)

该方法是四舍五入取整法,mode参数用于指定中间值的取法。

总结:

**总的来说,一般情况下,我们可以直接使用Round(decimal)和Round(decimal,Int32)来进行取整和小数的精度计算。 **

因为这两个方法的默认MidpointRounding属性已经够满足我们大部分的使用场景。对于特殊性的MidpointRounding.AwayFromZero的方式,视具体情况而定。

另外,Math.Round()方法笔者没有详细去考证,当可以推测其用法与本文所述的decimal.Round()用法应该是一致的。

标签: c#, round, 四舍五入, 取整

添加新评论