Formatting n significant digits in C++ without scientific notation

拈花ヽ惹草 提交于 2019-12-10 02:51:51

问题


I want to format a floating point value to n significant digits but never using scientific notation (even if it would be shorter).

The format specification %f doesn't deal in significant digits, and %g will sometimes give me scientific notation (which is inappropriate for my use).

I want values in the form "123", "12.3", "1.23" or "0.000000123".

Is there an elegant way to do this using C++ or boost?


回答1:


The best way I know (and use it in my own code) is

#include <string>
#include <math.h>
#include <sstream>
#include <iomanip>

int round(double number)
{
    return (number >= 0) ? (int)(number + 0.5) : (int)(number - 0.5);
}

std::string format(double f, int n)
{
    if (f == 0) {
        return "0";
    }            
    int d = (int)::ceil(::log10(f < 0 ? -f : f)); /*digits before decimal point*/
    double order = ::pow(10., n - d);
    std::stringstream ss;
    ss << std::fixed << std::setprecision(std::max(n - d, 0)) << round(f * order) / order;
    return ss.str();
}

c++11 has std::round so you won't need my version of with a new compiler.

The trick I'm exploiting here is to get the precision you want by taking the base 10 log to count the number of digits before the decimal and subtracting this from the precision you want.

It satisfies @Mats Petersson's requirement too, so will work in all cases.

The bit I don't like is the initial check for zero (so the log function doesn't blow up). Suggestions for improvement / direct editing of this answer most welcome.




回答2:


std::fixed and std::setprecision (and <iomanip> in general) are your friends.

std::cout << 0.000000123 << '\n';

prints 1.23e-07 and

std::cout << std::setprecision(15) << std::fixed << 0.000000123 << '\n';

prints 0.000000123000000

Just remember that floating-point numbers have limited precision, so

std::cout << std::fixed << 123456789012345678901234567890.0 << '\n';

will print 123456789012345677877719597056.000000 (probably not what you want)




回答3:


I think you'll have to remove trailing zeros by yourself :

string trimString(string str)
{
    string::size_type s;
    for(s=str.length()-1; s>0; --s)
    {
        if(str[s] == '0') str.erase(s,1);
        else break;
    }
    if(str[s] == '.') str.erase(s,1);
    return str;
}

Usage :

double num = 0.000000123;
stringstream ss;
ss << num;
ss.str("");
ss << std::setprecision(15) << std::fixed << num; // outputs 0.000000123000000
string str;
ss >> str;
str = trimString(str);
cout << str << endl;  // outputs 0.000000123

Put together :

string format(int prec, double d) {
    stringstream ss;
    ss << d;
    ss.str("");
    ss << std::setprecision(prec) << std::fixed << d;

    string str;
    ss >> str;
    string::size_type s;
    for(s=str.length() - 1; s > 0; --s)
    {
        if(str[s] == '0') str.erase(s,1);
        else break;
    }
    if(str[s] == '.') str.erase(s,1);
    return str;
}

Usage :

double num = 0.000000123;
cout << format(15, num) << std::endl;

If someone knows a better way ...



来源:https://stackoverflow.com/questions/17211122/formatting-n-significant-digits-in-c-without-scientific-notation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!