Math.Round error?

  • Thread starter Thread starter ng_mr
  • Start date Start date
N

ng_mr

No, not a question about "banker's rounding" or whatever it's called.


I want to round a double to the nearest 100th, so I perform the
following:

// original is a double
double result = Math.Round( original, 2 );

But I'm not happy with the results. E.g. if original is
-2533.85009765625 the result is -2533.85009765625 (as viewed in the
debugger and as output via displayed in the UI when converted to a
string.)

Also, if original is already a simple rounded value such as 10.23, the
resulting value is 10.229999542236328!!

Am I right to expect better results from Math.Round? Is this a bug in
the CLR? Is there a compiler switch or something that might affect
this?

Thanks,
Mel.
 
No, not a question about "banker's rounding" or whatever it's called.


I want to round a double to the nearest 100th, so I perform the
following:

// original is a double
double result = Math.Round( original, 2 );

But I'm not happy with the results. E.g. if original is
-2533.85009765625 the result is -2533.85009765625 (as viewed in the
debugger and as output via displayed in the UI when converted to a
string.)

Also, if original is already a simple rounded value such as 10.23, the
resulting value is 10.229999542236328!!

Am I right to expect better results from Math.Round? Is this a bug in
the CLR? Is there a compiler switch or something that might affect
this?

Thanks,
Mel.

see http://www.yoda.arachsys.com/csharp/floatingpoint.html

Hans Kesting
 
Thanks for the link.

But can I simply chalk it down to the precision (or lack of
precision?) of floating point values? From other people's sample code
it seems to me as though Math.Round should yield 'expected' results
most of the time, especially if input with the correct value in the
first place.

And if Math.Round cannot be relied upon to 'truly' round a floating
point value, should I actually be using String.Format instead of
Math.Round(....).ToString()?

Also, there's a mistake in the value of the variable named original in
my first post: it's value is -2533.849609375, which after undergoing
treatment under Math.Round yields -2533.85009765625.

Cheers,
Mel.
 
Can you post the code that shows your problem? I've tried rounding the
number with .NET 1.1 and 2.0 and it returns the correct result for both
versions.

Stefan
 
Hi Stefan,

Sure, here's some code that I've just run and shows the problem:

double original = 1234.56;
double rounded = System.Math.Round( original, 2 );
Debug.WriteLine( rounded );

And the output from Debug.WriteLine is:
1234.56005859375

This is also the value displayed in the watch window for the rounded
variable.

The bizarre thing is that if I start a new, simple project and put the
above lines of code in, the rounded value is 1234.56. But the project
I need a fix for is a large multi-layered one with a plug-in
architecture. Some unmanaged code is used in parts too. Could it be
some memory leaks or corruption?

Thanks,
Mel.
 
Well, it's really hard to debug if the problem can't be repeated in an empty
solution. But I wouldn't expect it to be any memory corruption. But as for
the value, it seems more like
(double) 1234.56f, which yields 1234.56005859375 as well. Are you sure the
'original' variable is a double? If it is float, then the rounding function
called would be float Math.Round(float x, ...), which would return the same
number, and converting the result to double shows the lack of precision in
the float type.

HTH,
Stefan
 
Sure, here's some code that I've just run and shows the problem:

double original = 1234.56;
double rounded = System.Math.Round( original, 2 );
Debug.WriteLine( rounded );

And the output from Debug.WriteLine is:
1234.56005859375

That's not entirely surprising. 1234.56 isn't exactly representable as
a double. Try this:

using System;

class Test
{
static void Main()
{
double original = 1234.56;
double rounded = System.Math.Round( original, 2 );
Console.WriteLine (DoubleConverter.ToExactString(original));
Console.WriteLine (DoubleConverter.ToExactString(rounded));
}
}

(using DoubleConverter from
http://www.pobox.com/~skeet/csharp/DoubleConverter.cs)

The results are:
1234.55999999999994543031789362430572509765625
1234.55999999999994543031789362430572509765625

Note that the rounding hasn't done anything. That's natural, as your
original value was already the closest possible value to 1234.56.
 
I have en****ered the same problem.
In a complex .Net solution with COM components also, the Math.round doesn't work.
I suppose some kind of memory problem (leak or corruption) :-(
Testing in an empty solution it work.
 
Back
Top