In a C++ program, I want to display a column of floating point values so that the sign, digits, and decimal point all line up. Multiple leading zeros should pad the whole number part of each value, when necessary. For example:
A column of floating point values:
+000.0012
-000.0123
+000.1235
-001.2346
+012.3457
-123.4568
I had an elaborately commented test program that demonstrated the problem. But, as I was editing this post, I found the answer I need here:
- Extra leading zeros when printing float using printf?
The essential problem was that I was using a format code of "%+04.4f"
when I should use "%+09.4f"
, because the total field width I want is 9:
I do not have enough reputation points to comment on that post, so thank you from here, @AndiDog.
I still do not know how to get multiple leading zeros using just stream formatting flags. But that is a battle for another day. I will stick with a mixture of printf and stream for now.
Using %. 2f in printf. It only print 2 decimal points.
If the position of zero before bit is set to one, they are termed as leading zeros.
we now see that the format specifier "%. 2f" tells the printf method to print a floating point value (the double, x, in this case) with 2 decimal places. Similarly, had we used "%. 3f", x would have been printed rounded to 3 decimal places.
A couple of comments have mentioned std::setfill('0')
and std::setw
. While these are necessary, they're not sufficient to the task. For example, this code:
std::cout << std::setfill('0') << std::setw(7) << std::showpos << 0.012;
will produce: 0+0.012
as its output. This is obviously not quite what we wanted.
We need to add the std::internal
flag to tell the stream to insert "internal padding" -- i.e., the padding should be inserted between the sign and the rest of the number, so code like this:
std::cout << std::setfill('0') << std::setw(7) << std::internal << std::showpos << 0.012;
...produces the output we want: +00.012
.
Also note that the padding character is "sticky", so if you alternate between using std::setw
with numeric and non-numeric types, you'll probably need/want to change it each time. Otherwise, something like std::cout << setw(12) << name;
will produce results like: 0000000Jerry
, which is rarely desired either.
To assure that we always get the same number of places after the decimal point, we also need to set the std::fixed
flag, and specify the number of places with std::setprecision
, such as:
#include <iostream>
#include <iomanip>
#include <vector>
int main() {
std::vector<double> values { 0.1234, 1.234, 1.5555 };
for (auto d : values)
std::cout << std::internal << std::showpos << std::setw(9)
<< std::setprecision(3) << std::setfill('0') << d << "\n";
}
Which produces the output I believe is desired:
+0000.123
+0001.234
+0001.556
There is one circumstance under which you won't get aligned results this way though: if you have a number too large to fit into the field provided, all the places before the decimal point will still be printed. For example, if we added 1e10
to the list of numbers to be printed by the preceding code, it would be printed out as: +10000000000.000
, which obviously won't align with the rest.
The obvious way to deal with that would be to just put up with it, and if it arises often enough to care about, increase the field size to accommodate the larger numbers.
Another possibility would be to use fixed notation only the number is below a certain threshold, and switch to (for example) scientific notation for larger numbers.
At least in my experience, code like this tends to be used primarily for financial data, in which case the latter option usually isn't acceptable though.
To show the positive sign, you use std::showpos.
To show the leading zeros, you use std::setw(n) and std::setfill('0').
To show the digits after zero, you use std::setprecision(m).
To show the zeros between the + sign and the first digit, you use std::internal.
To keep the digit at a fixed position, you use std::fixed.
#include <iostream> // std::cout, std::fixed
#include <iomanip> // std::setprecision
int main () {
double f =1.234;
double g =-12.234;
std::cout << std::showpos<< std::internal << std::fixed << std::setprecision(4)<<std::setw(9) <<std::setfill('0') << f << '\n';
std::cout <<std::setw(9)<< std::setfill('0') <<g<<"\n"; //repeat these for a new number
return 0;
}
//output:
//+001.2340
//-012.2340
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With