Formatting for Float/Double Numbers

Have you ever formatted number output in COBOL? As you would have from the CSCI 465/565 class? Because if so, this next bit is going to look eerily familiar.

C# provides a great deal of control over how we display real numbers in our output. From how many digits appear before/after the decimal point, to whether we show the decimal point at all, left padding, right padding, or how negative numbers are represented. Other languages allow us to do this as well, but not many make it this concise. For example, if I wanted to display a real number, with only two digits after the decimal point, in a space at least 10 characters wide, and left-aligned within that space, I would do this, in C++:

cout << fixed << setprecision(2) << setw(10) << left << 3.141519265;

Which would print '3.14      '. But with C#, I can do:

Console.WriteLine(String.Format("{0, -10: 0.00}", 3.14159265));

Like I said: it's concise but might take some getting used to. Let's break this down: first and foremost, we're utilizing String.Format to provide the, well, format, of this output. The argument in the above example only prints a single real number, but we could easily modify it to look more like our other output statements. Such as:

Console.WriteLine(String.Format("Pi: {0, -10: 0.00}", 3.14159265));

The {0} notation is what we're simply expanding on, providing additional instructions for how that variable will be printed. That's what the first 0 represents, the 0th variable in the list that follows this format. To provide a minimum length buffer for the output value, you add either a positive (right-justified) or negative (left-justified) after a comma. For example, if I wanted to simply print any variable (not just real numbers) to have a certain minimum length buffer, I would code it as {0, 42}.

The directions after the colon character are what dictate the format the real number will take on when printed. A "0" character represents a digit that will be printed, no matter what. If no digit fills this space from the input value, a zero is output. For example:

Console.WriteLine(String.Format("Tau: {0: 00.00}", 6.283185)); // Prints Tau: 06.28 Console.WriteLine(String.Format("{0: 0.00}", 6.283185));       // Prints 6.28 Console.WriteLine(String.Format("{0: 0.00}", 6.2));            // Prints 6.20

If digits after the decimal point get truncated, the number will be rounded up before being printed. So ("{0: 0.00}", 0.999999) will print as 1.00 (don't be surprised if your math friends are seizing up at this point in the notes.)

You can also use a "#" character to represent a placeholder for a digit that will be left blank if not digit from the input value fills it. For example:

Console.WriteLine(String.Format("{0: ##.00}", 0.283185)); // Prints .28 Console.WriteLine(String.Format("{0: #0.00}", 6.283185)); // Prints 6.28 Console.WriteLine(String.Format("{0: 0.##}", 6));         // Prints 6

It's worth noting that multiple # placeholders to the left of the decimal point is redundant, such as the example up above. If I pass in a value < 10 or some value in the millions, they will be displayed exactly the same as if I used a single #. If you want to use thousands separators (comma), try:

Console.WriteLine(String.Format("The taxi cab number: {0: 0,0}", 1729));        // Prints 1,729 Console.WriteLine(String.Format("A palindromic prime: {0: 0,0}", 399878993)); // Prints 399,878,993

Here's the fun bit: you can substitute the printing of a negative sign with a word like "minus". Or substitute zero values to be printed as "zero".

Console.WriteLine(String.Format("{0: 0.00; minus 0.00; zero}", 123.4567));  // Prints 123.46 Console.WriteLine(String.Format("{0: 0.00; minus 0.00; zero}", -123.4567)); // Prints minus 123.46 Console.WriteLine(String.Format("{0: 0.00; minus 0.00; zero}", 0.0));       // Prints zero

Or if you wanted to just get weird:

Console.WriteLine(String.Format("{0: 00whyAmI.doingThis?00}", 123.4567));
// Prints 123whyAmI.doingThis?46


String.Format also includes modifiers for frequently utilized formats: representations of money (insertion of a floating dollar sign) and percentages.

Console.WriteLine(String.Format("{0: $0.00}", 123.4567)); // Prints $123.46
Console.WriteLine(String.Format("{0: 0.00%}", 0.1415)); // Prints 14.15%