Reputation: 6846
I'm trying to output a float as three digits, or more if necessary to avoid an exponent.
Some examples:
0.12 // 0.123 would be ok
1.23
12.3
123
1234
12345
The closest I've gotten is
std::cout << std::setprecision(3) << f << std::cout;
but this prints things like
21 // rather than 21.0
1.23e+03 // rather than 1234
Combining std::setprecision
with std::fixed
means I always get the same number of post-decimal digits, which is not what I want.
Using std::setw
, 123.456 would still print as 123.456 rather than 123.
Any suggestions?
Upvotes: 3
Views: 244
Reputation: 4387
As far as I can tell, the easiest way around this is to roll a function to catch it. I threw this together and it seems to work. I'm not sure if you wanted large numbers to only have 3 significant digits or if they should keep all sig figs to the left of the decimal place, but it wouldn't be hard to make that modification:
void printDigits(float value, int numDigits = 3)
{
int log10ofValue = static_cast<int>(std::log10(std::abs(value)));
if(log10ofValue >= 0) //positive log means >= 1
{
++log10ofValue; //add 1 because we're culling to the left of the decimal now
//The difference between numDigits and the log10 will let us transition across the decimal
// in cases like 12.345 or 1.23456 but cap it at 0 for ones greater than 10 ^ numDigits
std::cout << std::setprecision(std::max(numDigits - log10ofValue, 0));
}
else
{
//We know log10ofValue is <= 0, so set the precision to numDigits + the abs of that value
std::cout << std::setprecision(numDigits + std::abs(log10ofValue));
}
//This is a floating point truncate -- multiply up into integer space, use floor, then divide back down
float truncated = std::floor(value * std::pow(10.0, numDigits - log10ofValue)) / std::pow(10.0, numDigits - log10ofValue);
std::cout << std::fixed << truncated << std::endl;
}
Test:
int main(void)
{
printDigits(0.0000000012345);
printDigits(12345);
printDigits(1.234);
printDigits(12.345678);
printDigits(0.00012345);
printDigits(123456789);
return 0;
}
Output:
0.00000000123
12300
1.23
12.3
0.000123
123000000
Upvotes: 2
Reputation: 6846
Here's the solution I came up with. Ugly, but I believe it works.
if(f>=100) {
std::cout << std::fixed << std::setprecision(0) << f << std::endl;
std::cout.unsetf(std::ios_base::floatfield);
} else {
std::cout << std::showpoint << std::setprecision(3) << f << std::noshowpoint << std::endl;
}
If someone knows how to simplify this, please let me know!
Upvotes: 0