使用ostringstream将double格式化为字符串

Formatting double to string with ostringstream

本文关键字:字符串 格式化 double ostringstream 使用      更新时间:2023-10-16

我想将双精度转换为字符串,四舍五入到小数点后的2位。我希望1.009表示为"1.01",1.0表示为"1"。这就是我尝试过的:

std::ostringstream oss;
oss << std::fixed << std::setprecision(2) << std::noshowpoint  << 1.0;

它输出"1.00",尽管我从未设置宽度,甚至指定了std::noshowpoint。如何实现所需的表现?

最佳解决方案:

inline double twodec(double n) { return floor(n * 100 + 0.5) / 100; }
oss << twodec(1.0) << ' ' << twodec(1.009);

讨论

发件人http://www.cplusplus.com/reference/ios/fixed/(我的斜体字)

当floatfield设置为固定时,使用定点表示法写入浮点值,这意味着该值用表示,小数部分的位数与精度字段指定的位数完全相同,并且没有指数部分。

所以,"固定"是行不通的。

也就是说,我能想到的做你想做的事的唯一方法是:

  • 先将数字四舍五入到所需的精度(即floor(n * 100 + 0.5) / 100),然后使用默认表示形式(即不要指定固定的、科学的或精度-如果fixedscientific有效,请先用std::cout.unsetf(std::ios::floatfield)清除它们)
  • 根据点前后要查看的最大数字总数动态设置精度(这是精度指定的值);要做到这一点,您可以计算出小数点之前的部分需要多少位数(可能使用10为基数),然后加2
  • 将结果流式传输到ostringstream,然后删除后面的0和任何"."(相当可怕)

这是我基于Tony答案的最终解决方案:

template <typename T>
std::string stringForNumber( T f, int precision /* = 0 */, bool fixedWidth /*= false*/ )
{
    std::ostringstream ss;
    ss.setf(std::ios_base::fixed);
    if (precision > 0)
        ss << std::setprecision(precision);
    ss << f;
    std::string str(ss.str());
    if (!fixedWidth) // Removing trailing 0
    {
        const auto pointLocation = str.find_first_of(".,");
        if (pointLocation != std::string::npos)
        {
            const auto lastZeroPos = str.find_last_of('0');
            const auto lastNotZeroPos = str.find_last_not_of('0');
            if (lastNotZeroPos == pointLocation) // Integer number
                str.erase(pointLocation);
            else if (lastZeroPos != std::string::npos && lastNotZeroPos != std::string::npos && pointLocation < lastZeroPos && lastNotZeroPos < lastZeroPos)
            {
                str.erase(lastNotZeroPos+1);
            }
        }
    }
    return str;
}