double a = 18.565
return Math.Round(a,2)
..returns 18.57.
For every other number I tried banker's rounding worked as expected, for example Math.Round(2.565,2) returned 2.56.
Any clue why and when that happens? Is it error or am I missing something about banker's rounding?
Thanks..
Double is a floating point value, so maybe if you write it as 18.565, it is actually in memory something like 18.56500000000000000000000000000000001, and hence it is more than the midpoint.
My guess is that the FP representation means it isn't actually a trailing 5; the dangers of FP!
This works fine, though:
As Matthew said, 18.565 can't be accurately represented. The actual value used is 18.565000000000001278976924368180334568023681640625 (found using DoubleConverter), which is clearly beyond half-way. Now I've a sneaking feeling that sometimes
Math.Round
will consider a value which is actually beyond the half-way point, but which is as close to the half-way point as can be accurately represented, as being exactly at that point. However, I haven't seen any documentation describing the situations in which that's applied, and clearly it's not happening in this case. I wouldn't want to rely on it.Even the rounded value isn't exactly 18.57 of course. It's actually 18.57000000000000028421709430404007434844970703125.
Fundamentally, if you really, really care about representing decimal values accurately, you should be using
decimal
. That's not just in terms ofMath.Round
- it goes to every aspect of handling floating point values.That does give the right value for
Math.Round
, of course:18.565 can not be exactly represented as a double. Thus, the binary representation is slightly higher, so it rounds up. If you use decimal:
it can be exactly represented, and you won't have this issue.