.NET Forum / .NET Framework / New Users / August 2006
Math.Round
|
|
Thread rating:  |
FrankVDL@gmail.com - 01 Sep 2005 14:27 GMT Hi,
C# uses Banker's Rounding to round decimals
1.75 -> 1.8 1.65 -> 1.6
How can I disable this Banker's rounding !!! I would prefere that when the double ends on 5, it gets roudend up (ignoring even/odd numbers)
1.75 -> 1.8 1.65 -> 1.7
Kind Regards Frank Vanderlinden
Stefan Misch - 01 Sep 2005 15:04 GMT Frank,
very interesting feature, as I'm just starting my C# adventure. Up to now I did not find any hint if .NET allows you to choose between different rounding algorithms. At least you would suppose that System.Math would provide a property if this would be the case.
The most promising link was http://support.microsoft.com/default.aspx?scid=kb;en-us;196652 As this document was revised in 2004 I guess that MS would have added a hint for the .NET framework. I'll get back if I find anything better.
Stefan
> Hi, > [quoted text clipped - 12 lines] > Kind Regards > Frank Vanderlinden Stefan Misch - 01 Sep 2005 16:06 GMT What makes me a bit nervous is this: Console.WriteLine("Implicit rounding by formatting: {0} results in {0:0.0}", 1.75); Console.WriteLine("Implicit rounding by formatting: {0} results in {0:0.0}", 1.65);
results in: Implicit rounding by formatting: 1,75 results in 1,8 Implicit rounding by formatting: 1,65 results in 1,7
So rounding is not consistent!
> Frank, > [quoted text clipped - 26 lines] >> Kind Regards >> Frank Vanderlinden Damien - 01 Sep 2005 15:42 GMT > Hi, > [quoted text clipped - 12 lines] > Kind Regards > Frank Vanderlinden Hi Frank,
it doesn't look like there is a way to get it other than by rolling your own. E.g. (off the top of my head, not tested, and a VB snippet since that's where I work (not tested cause my machine is groaning at the moment and may very well collapse thorugh lack of memory, so cannot fire up VS)):
Public Function MyRound(ByVal num as Double,ByVal prec as int32) as Double Dim rnd1 as Double = Math.Round(num,prec) If rnd1 < num AndAlso num-rnd1 = (5 * 10 ^ -prec) Then rnd1 = rnd1 + (1 * 10 ^ -(prec-1)) End If Return rnd1 End Function
HTH,
Damien
William Stacey [MVP] - 01 Sep 2005 15:50 GMT decimal d1 = 1.65m;
decimal d2 = 1.75m;
d1 = Math.Round(d1, 1, MidpointRounding.AwayFromZero);
d2 = Math.Round(d2, 1, MidpointRounding.AwayFromZero);
Console.WriteLine(d1);
Console.WriteLine(d2);
Also see http://msdn2.microsoft.com/library/17w4143s(en-us,vs.80).aspx
Not sure if this is new to 2.0 or not, but the above works on 2.0.
 Signature William Stacey [MVP]
> Hi, > [quoted text clipped - 12 lines] > Kind Regards > Frank Vanderlinden FrankVDL@gmail.com - 01 Sep 2005 16:05 GMT ok, next problem ...
using your codesnippet, but adjusting the Console.Writeline method ...
Printing the same value in two different ways !
Console.WriteLine(string.Format{"{0:0.00} - {0}", d1);
this will return "1.7- 1.6"
How can this be explained ?
William Stacey [MVP] - 01 Sep 2005 19:18 GMT Not sure. d1 is always the same. It must be something Format is doing.
 Signature William Stacey [MVP]
> ok, next problem ... > [quoted text clipped - 7 lines] > > How can this be explained ? FrankVDL@gmail.com - 01 Sep 2005 19:36 GMT Sorry, i've copied the wrong line of code, this should be it
Console.WriteLine(string.Format{"{0:0.0} - {1}", d1, Math.Round(d1, 1));
However I'm using the same value, this is the result :"1.7- 1.6"
Stefan Misch - 01 Sep 2005 16:28 GMT This is a new feature of 2.0 (see the end of the link you provided).
> decimal d1 = 1.65m; > [quoted text clipped - 28 lines] >> Kind Regards >> Frank Vanderlinden FrankVDL@gmail.com - 01 Sep 2005 22:44 GMT Banker's Rounding can't be used in real life !!!
Check the following example: it's a simple presentation of a ticket.
double[] lines = new double[5];
//Set some VAT's lines[0] = 1.245; lines[1] = 1.246; lines[2] = 1.241; lines[3] = 1.275; lines[4] = 1.255;
//Print and calc total double tot = 0; foreach (double val in lines) { tot += val; Console.WriteLine(" {0:0.00}", val); } Console.WriteLine("-----"); Console.WriteLine(" {0:0.00}", tot);
Console.ReadLine();
This is the result :
1,25 1,25 1,24 1,28 1,26 -------- 6,26
Now take our your calculator (or excell if you like) an add the 5 lines manualy !
Your result wil be 6.28. -> 0.02 difference !!!!!!!!!
If I give this ticket to a client he demands to now where the 0.02 euro has gone to.
Is there a way I can disable the Banker's Rounding ( set 'MidpointRounding.AwayFromZero' as default) for the entire application !
Kind Regards Frank Vanderlinden
Jon Skeet [C# MVP] - 01 Sep 2005 22:48 GMT > Banker's Rounding can't be used in real life !!! It is - by banks, hence the name.
> Check the following example: it's a simple presentation of a ticket. > [quoted text clipped - 32 lines] > > Your result wil be 6.28. -> 0.02 difference !!!!!!!!! *Any* form of rounding will give that kind of result.
> Is there a way I can disable the Banker's Rounding ( set > 'MidpointRounding.AwayFromZero' as default) for the entire application > ! I don't know - but why not just specify it each time, or write your own method which calls Math.Round with the "right" parameters internally?
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet If replying to the group, please do not mail me too
FrankVDL@gmail.com - 01 Sep 2005 22:57 GMT These kind of calculations are done serveral times in my app.
I need to be sure that I (or some other developers in my team) doesn't forget to add the correct rounding.
As you can see in the code sample, I don't even use the round method. I'm just printing out some data ....
Jon Skeet [C# MVP] - 02 Sep 2005 06:31 GMT > These kind of calculations are done serveral times in my app. > [quoted text clipped - 3 lines] > As you can see in the code sample, I don't even use the round method. > I'm just printing out some data .... So that's what code reviews are for :)
You *may* be able to write an FxCop rule to check that you do the right thing, but it shouldn't be too hard to remember. We have a similar situation in our (Java) project at the moment - whenever we need to lower-case a string, we have to do it in the US locale, rather than just calling toLower(). It's pretty easy to spot it in code review though.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet If replying to the group, please do not mail me too
Osmar Fernandez - 16 Aug 2006 16:41 GMT I just Found this problem with Awayfromzero New Parameter Try This Sample and See the Result Math.Round(0.285, 2, MidpointRounding.AwayFromZero) The Result Should be 0.29 But Is not. Any Ideas?
Greg Young - 16 Aug 2006 21:53 GMT My guess is that this has to deal with floating point precision ...
0.285 there is not actually 0.285 (it is an approximation which is just below 0.285)
If you use a decimal it comes out properly
Cheers,
Greg Young MVP - C# http://codebetter.com/blogs/gregyoung
>I just Found this problem with Awayfromzero New Parameter > Try This Sample and See the Result [quoted text clipped - 3 lines] > > *** Sent via Developersdex http://www.developersdex.com *** NormD - 31 Aug 2006 19:19 GMT I happened to see this. Sometimes a "roundoff rule" is used in systems. If the last digit is 5, round up to make the previous digit even (or odd), otherwise truncate. DEpending on the "rule" rounding off 0.285 could be 0.29 or 0.28. If it really is anything more than 0.2850000... then I'd expect it to round up to 0.29 for the reason you gave. Rounding and truncating are not the same thing.
> My guess is that this has to deal with floating point precision ... > [quoted text clipped - 16 lines] > > > > *** Sent via Developersdex http://www.developersdex.com ***
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|