Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does .Net use a rounding algorithm in String.Format that is inconsistent with the default Math.Round() algorithm?

I've noticed the following inconsistency in C#/.NET. I was wondering why it is so.

Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.04, Math.Round(1.04, 1)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.05, Math.Round(1.05, 1)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.06, Math.Round(1.06, 1)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.14, Math.Round(1.14, 1)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.15, Math.Round(1.15, 1)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.16, Math.Round(1.16, 1)); Console.WriteLine(); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.04, Math.Round(1.04, 1, MidpointRounding.AwayFromZero)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.05, Math.Round(1.05, 1, MidpointRounding.AwayFromZero)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.06, Math.Round(1.06, 1, MidpointRounding.AwayFromZero)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.14, Math.Round(1.14, 1, MidpointRounding.AwayFromZero)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.15, Math.Round(1.15, 1, MidpointRounding.AwayFromZero)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.16, Math.Round(1.16, 1, MidpointRounding.AwayFromZero)); 

Output:

1.0  | 1.0 1.1  | 1.0 1.1  | 1.1 1.1  | 1.1 1.2  | 1.2 1.2  | 1.2  1.0  | 1.0 1.1  | 1.1 1.1  | 1.1 1.1  | 1.1 1.2  | 1.2 1.2  | 1.2 

It appears that the default string formatting behaviour is to round using MidpointRounding.AwayFromZero rather than Math.Round()'s default of MidpointRounding.ToEven.

like image 712
orj Avatar asked Feb 09 '10 01:02

orj


People also ask

Does string format round up?

If the value to be formatted has more than the specified or default number of decimal places, the fractional value is rounded in the result string. If the value to the right of the number of specified decimal places is 5 or greater, the last digit in the result string is rounded away from zero.

What is formatting strings in C#?

In C#, Format() is a string method. This method is used to replace one or more format items in the specified string with the string representation of a specified object.In other words, this method is used to insert the value of the variable or an object or expression into another string.


2 Answers

As a historical note, the original Visual Basic implementation of Format$ also was inconsistent with round-to-even, aka, Banker's Rounding. The original Format$ code was written by Tim Paterson. You might recall that Tim was the author of a little program called QDOS (later known as MS-DOS) that was rather a good seller for a while there.

Perhaps this is yet another case of 25 years of backwards compatibility.

like image 124
Eric Lippert Avatar answered Oct 09 '22 04:10

Eric Lippert


Seems this problem is worse than a "simple" inconsistency:

double dd = 0.034999999999999996;  Math.Round(dd, 2); // 0.03 Math.Round(dd, 2, MidpointRounding.AwayFromZero); // 0.03 Math.Round(dd, 2, MidpointRounding.ToEven); // 0.03  string.Format("{0:N2}", dd); // "0.04" 

This is absolutely bananas. Who knows where the heck it get "0.04" from.

like image 37
osexpert Avatar answered Oct 09 '22 05:10

osexpert