如何使用STL将数字格式化为有效数字

时间:2011-09-23 22:00:11

标签: c++ stl

我正在尝试使用C / C ++格式化数字到特定的有效位数,最好是STL。我已经看到在Javascript(toPrecision())和.Net中执行此操作的示例,但我在C / C ++中找不到任何相关内容。我想创建一个像这样的函数:

std::string toPrecision(double value, int significantDigits) {
    std::string formattedString;
    // magic happens here
    return formattedString;
}

因此它会产生如下结果:

toPrecision(123.4567, 2) --> "120"
toPrecision(123.4567, 4) --> "123.4"
toPrecision(123.4567, 5) --> "123.45"

有谁知道这样做的好方法?我正在考虑将整个数字转换成一个字符串然后只是扫描它以找到非零数字并以某种智能方式计算它们,但这看起来很麻烦。

我还可以将源代码下载到其中一个浏览器中,看看他们的toPrecision函数是什么样的,但我认为我需要整天来处理不熟悉的代码。希望有人可以帮忙!

4 个答案:

答案 0 :(得分:4)

another question被盗:

#include <string>
#include <sstream>
#include <cmath>
#include <iostream>

std::string toPrecision(double num, int n) {
    https://stackoverflow.com/questions/202302/rounding-to-an-arbitrary-number-of-significant-digits

    if(num == 0) {
      return "0";
    }

    double d = std::ceil(std::log10(num < 0 ? -num : num));
    int power = n - (int)d;
    double magnitude = std::pow(10., power);
    long shifted = ::round(num*magnitude);

    std::ostringstream oss;
    oss << shifted/magnitude;
    return oss.str();
}

int main() {
  std::cout << toPrecision(123.4567, 2) << "\n";
  std::cout << toPrecision(123.4567, 4) << "\n";
  std::cout << toPrecision(123.4567, 5) << "\n";
}

答案 1 :(得分:1)

在iomanip中查看setprecision()。这应该做你正在寻找的双倍,然后只需转换为字符串

答案 2 :(得分:0)

将其打印到ostringstream,根据需要设置浮点格式化参数。

答案 3 :(得分:0)

上面带有 ceil(log10(x)) 的方法对于确定数字整数部分的位数是完全合法的。但是我觉得只是为了设置一个数字而调用数学函数对CPU来说有点沉重。

将浮点值转换为数字过多的字符串,然后处理字符串本身不是更简单吗?

这是我要尝试的(使用 Qt 而不是 STL):

QString toPrecision(double num, int n) {
    QString baseString = QString::number(num, 'f', n);
    int pointPosition=baseString.indexOf(QStringLiteral("."));
    // If there is a decimal point that will appear in the final result
    if (pointPosition != -1 && pointPosition < n) 
        ++n ; // then the string ends up being n+1 in length                                    
    if (baseString.count() > n) {
        if (pointPosition < n) {
            baseString.truncate(n);
        } else {
            baseString.truncate(pointPosition);
            for (int i = n ; i < baseString.count() ; ++i)
                baseString[i]='0';
        }
    } else if (baseString.count() < n) {
        if (pointPosition != -1) {
            for (int i = n ; i < baseString.count() ; ++i)
                baseString.append('0');
        } else {
            baseString.append(' ');
        }
    }
    return baseString ;
}

但问题是关于 STL.. 所以,让我们这样重写:

std::string toPrecision(double num, size_t n) {
    std::ostringstream ss;
    ss << num ;
    std::string baseString(ss.str());
    size_t pointPosition=baseString.find('.');
    if (pointPosition != std::string::npos && pointPosition < n)
        ++n ;
    if (baseString.length() > n) {
        if (pointPosition < n) {
            baseString.resize(n);
        } else {
            baseString.resize(pointPosition);
            for (size_t i = n ; i < baseString.length() ; ++i)
                baseString[i]='0';
        }
    } else if (baseString.length() < n) {
        if (pointPosition != std::string::npos) {
                baseString.append(n-baseString.length(),'0');
        } else {
            baseString.append(n-baseString.length(),' ');
        }
    }
    return baseString ;
}