I have a bug with Math.Round with no explanation. When I make
Math.Round(81.725, 2, MidpointRounding.AwayFromZero)
The result is 81,72 but when I make the same with Decimal.Round
Decimal.Round(81.725M, 2, MidpointRounding.AwayFromZero)
The result is 81,73
I d'ont understand why, have you an solution to use Math.Round systematically ?
You shouldn't be talking about bugs before understanding how double
works, and the differences with decimal
that explain the behavior you are seeing.
A double is the best approximation of a real number with the following structure:
number = sign * mantissa * 2 ^ exponent
Therefore, the number 81.725,
when represented as a double
, is really:
1 * 2875442808959795 * 2^-45 = 81,724999999999994315658113919199
Now you should understand why Math.Round(81.725, 2)
resolves to 81.72
and not 81.73
.
This doesn't happen with decimal
because decimal
, contrary to double
, can exactly represent 81.725
. This is due to the fact that the scaling factor in decimal
is a power of 10
.
This added precision obviously comes at a cost, in speed, space and range. When to choose one type or the other is well explained in a link to another SO question provided in comments.
The M
suffix on second assignment below determines data type:
Math.Round(81.725, 2, MidpointRounding.AwayFromZero); // double, returns 81.72
Math.Round(81.725M, 2, MidpointRounding.AwayFromZero); // decimal, returns 81.73
Decimal.Round(81.725M, 2, MidpointRounding.AwayFromZero); // decimal, returns 81.73
By using that suffix, the given data type on second assignment treated as decimal
instead of double
, makes the rounding more precise.
The MSDN documentation of Math.Round already mention this difference:
Notes to Callers:
Because of the loss of precision that can result from representing decimal values as floating-point numbers or performing arithmetic operations on floating-point values, in some cases the
Round(Double)
method may not appear to round midpoint values to the nearest even integer.
And there is further explanation for Decimal.Round :
The behavior of this method follows IEEE Standard 754, section 4. This kind of rounding is sometimes called round half to even or banker's rounding. It minimizes rounding errors that result from consistently rounding a midpoint value in a single direction. It is equivalent to calling the
Round(Decimal, MidpointRounding)
method with a mode argument ofMidpointRounding.ToEven
.
In short, decimal
uses IEEE-754 which uses consistent rounding for midpoint value, while double
(and float
) uses floating-point which has no finite binary representation.
Other reference:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.