问题
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:
- 1 for the sign
- 3 for the whole digits
- 1 for the decimal point
- 4 for the fractional digits
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.
回答1:
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.
回答2:
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
回答3:
The only way I now how to do this is to display the sign first and then set the fill, width and precision after and display the positive value as you have already displayed the sign. You also need to set the format flag to ios::fixed
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
float x[] = { 000.0012, .0123, .1235, 1.2346, 12.3457, 123.4568 };
cout.setf(ios::fixed);
for (int i = 0; i < 6; i++)
cout << (x[i] > 0 ? '+' : '-') << setfill('0') << setw(8) << setprecision(4) << abs(x[i]) << endl;
return 0;
}
Displays
+000.0012
-000.0123
+000.1235
-001.2346
+012.3457
-123.4568
来源:https://stackoverflow.com/questions/30330148/how-to-display-multiple-leading-zeros-for-floating-point-values-in-c