Throughout my years as a developer I have had to figure out the syntax for formatting floating point numbers using printf, sprintf, and the like repeatedly. I always remember the basics, but as soon as I have questions about details it’s very difficult to find a good explanation. The man pages and web sites just sort of gloss over the details. I will focus only on floating point numbers and attempt to cover the topic in a more in depth manner than I’ve found elsewhere
If you are on a Mac or Linux you can try out your printf formatting strings directly from the terminal using the printf command. Here’s the one we’ll be using which will allow us to see any spaces that are created in the output.
printf '"%[format]f"\n' [number]
Basically this says: print a double quote followed by the formatted number followed by another double quote and then a newline. Again it’s important to note that we have the double quotes there because printf will sometimes pad the output with spaces and we want those to be clear.
There are two parts to the formatting of a float using printf. The field width and the precision.
%[field_width][precision]f
field_width
- default value
-
01 - meaning
This number represents the minimum width in characters of the output for this particular field. It has no numerical meaning, it just means that the output for this field will be at least this wide. It’s very easy, because of the way this is written, to get the idea that this represents the size of the whole number part of the output, but it does not.
To achieve this minimum string size, if necessary, the output will be padded on the left with one of two characters. If the value for this parameter begins with a
'0'it will be padded with'0'characters. If not, it will be padded with spaces.There is no way to effectively specify
'0'here meaning, “don’t show anything for the whole part of the number” or, “don’t show anything at all even if there isn’t a number”. A value of'0'will always act exactly like a value of'01'. For instance:printf '"%0.0f"\n'"0"A number isn’t even provided as input and this output is still produced. In fact the entire whole number part of the input will always, in all cases, be output. So printf can’t be your only tool if your goal is to just show just the fractional part of a number.
precision
- default value
.6- meaning
-
This is the width of the fractional part of the output not including the decimal point. This width takes the highest precedence and will be output no matter what. The output will be padded with zeros on the right side if the input is not this long. This length overrides a shorter field width value. For instance:
printf '"%4f"\n' 12.34"12.340000"So the minimum length of the field output will be this value plus one for the decimal point, plus the length of the whole number portion, which we know will be at least 1 because a
'0'will always be printed at the very least for the whole number.This effectively means printf can not be used to show the “natural” fractional length of any input.
printf will round numbers to produce output, it doesn’t just trunctate, so:
printf '"%0.1f"\n' 12.38"12.4"This example also shows that printf does fine if you need to produce the “natural” length of the whole number part, just not the fractional part. And as you’re beginning to see, printf makes a lot of decisions for you that you can’t change.
Useful Examples
printf '"%5.2f"\n' 3.14159
" 3.14"
printf '"%05.2f"\n' 3.14159
"03.14"
See how only one space or zero is added to make five total characters for the field width. These days, padding with spaces is not so useful because the web will ignore extra spaces. This feature was there to make it easier to produce columnar output for monospaced terminals.
This means that for most people reading this, specifying '0', '01', or nothing at all for the field width is the right thing to do in most cases.
printf '"%05.f"\n' 3.14159
printf '"%05.0f"\n' 3.14159
"00003"
Specifying '.0' or just '.' as the precision is the same thing, and will result in the decimal point not being shown either. Note the field width is still the specified 5 characters.
One Comment
Swetlana
excellent, thanks for that!