Reputation: 4857
I would like to print a double
value, into a string of no more than 8 characters. The printed number should have as many digits as possible, e.g.
5.259675
48920568
8.514e-6
-9.4e-12
I tried C++ iostreams, and printf
-style, and neither respects the provided size in the way I would like it to:
cout << setw(8) << 1.0 / 17777.0 << endl;
printf( "%8g\n", 1.0 / 17777.0 );
gives:
5.62525e-005
5.62525e-005
I know I can specify a precision, but I would have to provide a very small precision here, in order to cover the worst case. Any ideas how to enforce an exact field width without sacrificing too much precision? I need this for printing matrices. Do I really have to come up with my own conversion function?
A similar question has been asked 5 years ago: Convert double to String with fixed width , without a satisfying answer. I sure hope there has been some progress in the meantime.
Upvotes: 6
Views: 1213
Reputation:
If you want to convert to fixed decimal numbers (e.g. drop the +/-"E" part), then it makes it a lot easier to accomplish:
#include <stdio.h>
#include <cstring> // strcpy
#include <iostream> // std::cout, std::fixed
#include <iomanip> // std::setprecision
#include <new>
char *ToDecimal(double val, int maxChars)
{
std::ostringstream buffer;
buffer << std::fixed << std::setprecision(maxChars-2) << val;
std::string result = buffer.str();
size_t i = result.find_last_not_of('\0');
if (i > maxChars) i = maxChars;
if (result[i] != '.') ++i;
result.erase(i);
char *doubleStr = new char[result.length() + 1];
strcpy(doubleStr, (const char*)result.c_str());
return doubleStr;
}
int main()
{
std::cout << ToDecimal(1.26743237e+015, 8) << std::endl;
std::cout << ToDecimal(-1.0, 8) << std::endl;
std::cout << ToDecimal(3.40282347e+38, 8) << std::endl;
std::cout << ToDecimal(1.17549435e-38, 8) << std::endl;
std::cout << ToDecimal(-1E4, 8) << std::endl;
std::cout << ToDecimal(12.78e-2, 8) << std::endl;
}
Output:
12674323
-1
34028234
0.000000
-10000
0.127800
Upvotes: 0
Reputation: 283893
This seems not too difficult, actually, although you can't do it in a single function call. The number of character places used by the exponent is really quite easy to predict:
const char* format;
if (value > 0) {
if (value < 10e-100) format = "%.1e";
else if (value < 10e-10) format = "%.2e";
else if (value < 1e-5) format = "%.3e";
}
and so on.
Only, the C standard, where the behavior of printf is defined, insists on at least two digits for the exponent, so it wastes some there. See c++ how to get "one digit exponent" with printf
Incorporating those fixes is going to make the code fairly complex, although still not as bad as doing the conversion yourself.
Upvotes: 1