Math.Round problem

D

David Coleman

I am running VS 2003 and have applied SP1. (On WinXP SP2, .Net 1.1)

In the Command Window I get the following

? Math.Round(0.715, 2)
0.72
? Math.Round(0.725, 2)
0.72
? Math.Round(0.735, 2)
0.74

That is not a typo. ? Math.Round(0.725, 2) indeed returns 0.72.

This appears to be the reason I get a 1 cent rounding difference in certain
situations in my code.

The workaround I have implemented is of the form Math.Round(val + 1e-12,
places); however it's pretty ugly.

Help would be appreciated, thanks,

David.
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

David said:
I am running VS 2003 and have applied SP1. (On WinXP SP2, .Net 1.1)

In the Command Window I get the following

? Math.Round(0.715, 2)
0.72
? Math.Round(0.725, 2)
0.72
? Math.Round(0.735, 2)
0.74

That is not a typo. ? Math.Round(0.725, 2) indeed returns 0.72.

This appears to be the reason I get a 1 cent rounding difference in certain
situations in my code.

The workaround I have implemented is of the form Math.Round(val + 1e-12,
places); however it's pretty ugly.

That is a classic floating point problem.

If it is a problem for you, then floating point is
probably not the correct data type.

Maybe you should use decimal ??

BTW, your workaround can create other problems if you numbers
can take full range.

Arne
 
J

John B

David said:
I am running VS 2003 and have applied SP1. (On WinXP SP2, .Net 1.1)

In the Command Window I get the following

? Math.Round(0.715, 2)
0.72
? Math.Round(0.725, 2)
0.72
? Math.Round(0.735, 2)
0.74

That is not a typo. ? Math.Round(0.725, 2) indeed returns 0.72.

This appears to be the reason I get a 1 cent rounding difference in certain
situations in my code.

The workaround I have implemented is of the form Math.Round(val + 1e-12,
places); however it's pretty ugly.

Help would be appreciated, thanks,

David.
I think you want the MidpointRounding.AwayFromZero enum value.
If you always want to round 5 "up" (down if less than zero) then this is
what you want.

By default it appears to use MidpointRounding.ToEven which will round
towards the nearest even number.
Ie .115 will be rounded to .12, .125 will also be rounded to .12.


HTH

JB
 
J

John B

John said:
I think you want the MidpointRounding.AwayFromZero enum value.
If you always want to round 5 "up" (down if less than zero) then this is
what you want.

By default it appears to use MidpointRounding.ToEven which will round
towards the nearest even number.
Ie .115 will be rounded to .12, .125 will also be rounded to .12.

oops, Math.Round(value, decimalplaces, MidpointRounding.AwayFromZero) :)
 
D

David Coleman

Thanks John B,

Explains the problem. But with VS 2003 Math.Round doesn't have a
MidpointRounding parameter overload.

All my business type calculations are done in static methods in calculations
classes so it's no big deal to do the fudge code for now.

Cheers,

David.
 
J

John B

David said:
Thanks John B,

Explains the problem. But with VS 2003 Math.Round doesn't have a
MidpointRounding parameter overload.

All my business type calculations are done in static methods in calculations
classes so it's no big deal to do the fudge code for now.

Hmm, didnt know that about 1.1.
A "hack" suggested in a previous post
http://groups.google.com.au/group/m...h.round+bankers&rnum=2&hl=en#184df858f6200f1e
is to call ToString("#.##") which does 5/4 rounding.
<...>

:(

JB
 
J

Jon Skeet [C# MVP]

David Coleman said:
I am running VS 2003 and have applied SP1. (On WinXP SP2, .Net 1.1)

In the Command Window I get the following

? Math.Round(0.715, 2)
0.72
? Math.Round(0.725, 2)
0.72
? Math.Round(0.735, 2)
0.74

That is not a typo. ? Math.Round(0.725, 2) indeed returns 0.72.

Which is exactly what the documentation says it will do.

<quote>
Return Value
The number nearest value with a precision equal to digits. If value is
halfway between two numbers, one of which is even and the other odd,
then the even number is returned. If the precision of value is less
than digits, then value is returned unchanged.
</quote>

If you're using .NET 2.0 and want a different sort of rounding, specify
a MidpointRounding to use.
 
C

Christof Nordiek

Another workaround:

Math.Ceiling((0.725 * 100)+.5)/100

----- Original Message -----
From: "David Coleman" <[email protected]>
Newsgroups: microsoft.public.dotnet.languages.csharp
Sent: Wednesday, September 20, 2006 5:25 AM
Subject: Math.Round problem
 
P

PS

David Coleman said:
I am running VS 2003 and have applied SP1. (On WinXP SP2, .Net 1.1)

In the Command Window I get the following

? Math.Round(0.715, 2)
0.72
? Math.Round(0.725, 2)
0.72
? Math.Round(0.735, 2)
0.74

That is not a typo. ? Math.Round(0.725, 2) indeed returns 0.72.

This appears to be the reason I get a 1 cent rounding difference in
certain situations in my code.

The workaround I have implemented is of the form Math.Round(val + 1e-12,
places); however it's pretty ugly.

This is known as banker's rounding. When working with rounding, always
rounding 0.5 up is not really fair. When dealing with money there would be a
bias. Compare the totals of your examples using the original numbers and the
rounded numbers. On the original total of 2.175 you want the total of the
rounded numbers to be 2.19 but using the examples you provided the total is
2.18.

If you have used the same rounding rules everywhere you should not have
rounding differences. However, you can't expect the total of rounded numbers
to equal the rounded total though. You will almost certainly have rounding
errors which is why you probably have a 1 cent difference. You need to
decide on a) what type of rounding you want and b) will you keep the rounded
figure or the original figure. If you keep the original figure then be
prepared for rounding errors like 0.03 + 0.03 + 0.03 = 0.10 (because 0.03
was really 0.034).

HTH

PS
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Arne said:
That is a classic floating point problem.

If it is a problem for you, then floating point is
probably not the correct data type.

Maybe you should use decimal ??

As other has pointed out, then the reason for the numbers
above being rounded as they are is the bankers rounding
(I did know that Round did bankers rounding).

But my point is still valid. You can not expect results that
make sense from a decimal number system perspective
when you use floating point.

Console.WriteLine(Math.Round(1.015, 2));
Console.WriteLine(Math.Round(2.015, 2));
Console.WriteLine(Math.Round(3.015, 2));
Console.WriteLine(Math.Round(4.015, 2));
outputs:

1,01
2,02
3,02
4,01

The correct solution is to use decimal. And specify the rounding
you want (I suspect that Round decimal is also using bankers
rounding by default).

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top