I have a float that I would like to print to exactly N spaces. For example, with N = 5. I want to get the following numbers printed as so:
0.1 => 0.1
123.456789 => 123.5
-123.45678 => -123 (or -123.)
0.123456 => 0.123
123456.789 => 123456 (obviously, in this case, we cannot print less than 6 digits, if I can detect this, I can also print 12** to indicate the field is too wide.
I have tried many combination including the following:
// Leave 3 extra space: One for negative sign, one for zero, one for decimal
std::cout << std::setiosflags(std::ios::fixed)
<< std::setprecision(N - 3)
<< std::setw(N)
<< input;
But the results are not favorable. Perhaps I am missing something obvious?
The output of the given code for those sample inputs are
0.10 // not bad
123.46 // Use 6 instead of 5 spaces
-123.46 // Use 7 instead of 5 spaces
0.12 // Under-use the spaces
123456.79 // Ok, I guess
Use Boost's Spirit.Karma for this:
#include <boost/spirit/include/karma.hpp>
namespace karma = boost::spirit::karma;
double d = 12345.6;
// will print: 12345
std::cout << karma::format(
karma::maxwidth(5)[karma::double_], d
) << std::endl;
which will limit the width of your output to 5 in any case. If you want to catch the case where the number would be cut off (as in your example for 123456.7), just perform the appropriate check up front:
if (d < 1e6) {
// d == 12345 will print: 12345
std::cout << karma::format(
karma::maxwidth(5)[karma::double_], d
) << std::endl;
}
else {
// d == 123456 will print: 12***
std::cout << karma::format(
karma::left_align(5, '*')[
karma::maxwidth(2)[karma::double_]
], d
) << std::endl;
}
And yes, in case you might ask, Boost's Spirit.Karma is written using only Standard C++ features.
int main ()
{
const int N = 4;
double f = 123.456789;
// just use default floating-point notation to display N significant digits.
// no fixed or scientific notation work for your requirement.
// you can comment setf() line out if there is no one changing ios::floatfield.
cout.setf(0, ios::floatfield);
cout.precision(N);
cout << f << endl; // will print 123.5
}
[UPDATE] I should have tested for all cases provided. :D
#include <iostream>
#include <math.h>
using namespace std;
void print_test(double number)
{
const int N = 5; // should be greater than 2
double maxIntPart = pow(10.0, number >= 0 ? N - 2 : N - 3);
double fractpart, intpart;
fractpart = modf(number , &intpart);
ios_base::fmtflags prevNotation = cout.setf(0, ios::floatfield); // use default floating-point notation
streamsize prevPrecicion = cout.precision();
if( abs(intpart) > maxIntPart )
{
intpart = ceil(number);
if( abs(intpart) < maxIntPart * 10 )
{
cout << intpart << endl;
}
else
{
while( abs(intpart) >= maxIntPart )
{
intpart /= 10;
}
cout << (intpart > 0 ? floor(intpart) : ceil(intpart)) << "**" << endl;
}
}
else
{
if ( number < 0 )
{
cout.precision(N - 3);
}
else if ( intpart == 0)
{
cout.precision(N - 2);
}
else
{
cout.precision(N - 1);
}
cout << number << endl;
}
cout.setf(prevNotation, ios::floatfield);
cout.precision(prevPrecicion);
}
int main ()
{
print_test(0.1); // 0.1
print_test(123.456789); // 123.5
print_test(-123.45678); // -123
print_test(0.123456); // 0.123
print_test(-0.123456); // -0.12
print_test(123456.789); // 123**
print_test(-123456.789); // -12**
}
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