Why does Math.Round(2.5) return 2 instead of 3?

前端 未结 15 1779
灰色年华
灰色年华 2020-11-22 03:54

In C#, the result of Math.Round(2.5) is 2.

It is supposed to be 3, isn\'t it? Why is it 2 instead in C#?

15条回答
  •  长情又很酷
    2020-11-22 04:38

    That's called rounding to even (or banker's rounding), which is a valid rounding strategy for minimizing accrued errors in sums (MidpointRounding.ToEven). The theory is that, if you always round a 0.5 number in the same direction, the errors will accrue faster (round-to-even is supposed to minimize that) (a).

    Follow these links for the MSDN descriptions of:

    • Math.Floor, which rounds down towards negative infinity.
    • Math.Ceiling, which rounds up towards positive infinity.
    • Math.Truncate, which rounds up or down towards zero.
    • Math.Round, which rounds to the nearest integer or specified number of decimal places. You can specify the behavior if it's exactly equidistant between two possibilities, such as rounding so that the final digit is even ("Round(2.5,MidpointRounding.ToEven)" becoming 2) or so that it's further away from zero ("Round(2.5,MidpointRounding.AwayFromZero)" becoming 3).

    The following diagram and table may help:

    -3        -2        -1         0         1         2         3
     +--|------+---------+----|----+--|------+----|----+-------|-+
        a                     b       c           d            e
    
                           a=-2.7  b=-0.5  c=0.3  d=1.5  e=2.8
                           ======  ======  =====  =====  =====
    Floor                    -3      -1      0      1      2
    Ceiling                  -2       0      1      2      3
    Truncate                 -2       0      0      1      2
    Round(ToEven)            -3       0      0      2      3
    Round(AwayFromZero)      -3      -1      0      2      3
    

    Note that Round is a lot more powerful than it seems, simply because it can round to a specific number of decimal places. All the others round to zero decimals always. For example:

    n = 3.145;
    a = System.Math.Round (n, 2, MidpointRounding.ToEven);       // 3.14
    b = System.Math.Round (n, 2, MidpointRounding.AwayFromZero); // 3.15
    

    With the other functions, you have to use multiply/divide trickery to achieve the same effect:

    c = System.Math.Truncate (n * 100) / 100;                    // 3.14
    d = System.Math.Ceiling (n * 100) / 100;                     // 3.15
    

    (a) Of course, that theory depends on the fact that your data has an fairly even spread of values across the even halves (0.5, 2.5, 4.5, ...) and odd halves (1.5, 3.5, ...).

    If all the "half-values" are evens (for example), the errors will accumulate just as fast as if you always rounded up.

提交回复
热议问题