【问题标题】:Formatting n significant digits in C++ without scientific notation在没有科学计数法的情况下在 C++ 中格式化 n 个有效数字
【发布时间】:2013-06-17 03:52:10
【问题描述】:

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

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

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

有没有一种优雅的方式可以使用C++或boost做到这一点?

【问题讨论】:

  • 那么你想让 123456 也打印为 123000 吗?
  • @MatsPetersson,是的,这就是我要说的(但实际上我将百分比值格式化为 3 位有效数字,因此不会出现问题)
  • 可能不错,但我没有测试过:stackoverflow.com/a/15167203/1715716

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


【解决方案1】:

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(可能不是您想要的)

【讨论】:

  • 这些都不是我想要的。 “1.23e-07”是s.n.,我说过我想避免。 “0.000000123000000”是固定的小数位数,而我说的是固定的有效位数。
【解决方案2】:

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

#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 的要求,因此适用于所有情况。

我不喜欢的一点是初始检查为零(因此日志功能不会崩溃)。欢迎提出改进/直接编辑此答案的建议。

【讨论】:

  • 算不上优雅,但到目前为止最接近!谢谢。仍然打印在 S.N.虽然:format (0.00000123456, 3) 打印 1.23e-06
  • 好的,试试我修改后的答案。 Pint 说它很完美(但由于精度最高,现在更不优雅了)。
  • 看起来不错,非常感谢。整个问题令人沮丧,因为标准库中清楚地存在“有效数字”逻辑,但它与 S.N. 密不可分。方面。
  • 这是一个问题(我会尝试自己解决):如果 f 是 10 的幂并且 n > log10 f ,那么输出的末尾会有一个额外的零。例如format(100.0, 3) 是“100.0”,而它应该是“100”(或者理想情况下是“100.”,带有尾随小数点)。
  • 针对@bdesham 指出的问题,使用floor(..) + 1 而不是ceil(..) 正确格式化十的幂。
【解决方案3】:

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

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;

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-04
    • 1970-01-01
    相关资源
    最近更新 更多