在没有科学记数法的情况下格式化C ++中的n位有效数字

时间:2013-06-20 10:19:06

标签: c++ format scientific-notation boost-format

我想将浮点值格式化为n位有效数字,但从不使用科学记数法(即使它更短)。

格式规范%f不会处理有效数字,而%g有时会给我科学记数法(这对我来说不合适)。

我想要"123", "12.3", "1.23" or "0.000000123"形式的值。

使用 C ++或提升执行此操作是否优雅

3 个答案:

答案 0 :(得分:12)

我知道的最好方法(并在我自己的代码中使用它)是

#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有std :: round,所以你不需要我的新版本的编译器。

我在这里利用的技巧是通过取基数10日志计算小数点前的位数并从你想要的精度中减去它来获得你想要的精度。

它也满足@Mats Petersson的要求,所以在所有情况下都会有效。

我不喜欢的是初始检查为零(因此日志功能不会爆炸)。建议改进/直接编辑这个答案最受欢迎。

答案 1 :(得分:0)

std::fixedstd::setprecision(以及<iomanip>一般)是您的朋友。

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

打印1.23e-07

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

打印0.000000123000000

请记住,浮点数的精度有限,所以

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

将打印123456789012345677877719597056.000000(可能不是您想要的)

答案 2 :(得分:0)

我认为你必须自己删除尾随零:

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;
}

用法:

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

放在一起:

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;
}

用法:

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

如果有人知道更好的方式......