简体   繁体   中英

double to string conversion with fixed width

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, eg

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.

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.

If you want to convert to fixed decimal numbers (eg 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM