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

发布于 2024-12-06 06:21:36 字数 644 浏览 2 评论 0原文

我正在尝试使用 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 函数是什么样子,但我认为我需要一整天的时间来处理不熟悉的代码。希望有人可以帮忙!

I'm trying to format numbers to a specific number of significant digits using C/C++ and preferably STL. I've seen examples of doing this in Javascript (toPrecision()) and .Net, but I can't find anything on doing this in C/C++. I want to create a function something like this:

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

So that it produces results like this:

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

Does anyone know a good way to do this? I'm considering dumping the whole number into a string and then just scanning through it to find the non-zero digits and count them off in some intelligent way, but that seems cumbersome.

I could also download the source code to one of the browsers and just see what their toPrecision function looks like, but I think it would take me all day to work through the unfamiliar code. Hope someone can help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

等你爱我 2024-12-13 06:21:36

另一个问题窃取:

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

Stolen from 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";
}
我偏爱纯白色 2024-12-13 06:21:36

查看 iomanip 中的 set precision()。这应该做你在双精度上寻找的东西,然后只需转换为字符串

Check out setprecision() in iomanip. That should do what you are looking for on the double, then just convert to string

饮湿 2024-12-13 06:21:36

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

Print it to an ostringstream, setting the floating-point formatting parameters as appropriate.

伤感在游骋 2024-12-13 06:21:36

上面的方法使用 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 ;
}

The method above with a ceil(log10(x)) is perfectly legit to determine the number of digit of the integer part of a number. But I feel it's a bit heavy on CPU to call for maths functions just to set a number of digit.

Isn't that simpler to convert the floating value into a string with too many digits, then to work on the string itself?

Here is what I'd try (with Qt instead of the 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 ;
}

But the question was about the STL.. So, let's rewrite it that way:

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 ;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文