将float转换为具有精度和指定的十进制数字的字符串?


88

如何在指定精度和十进制数字的同时将浮点数转换为C ++中的字符串?

例如: 3.14159265359 -> "3.14"


为什么不创建具有所需精度的临时浮点数,然后将其转换为字符串?
吉拉德(Gilad)2015年

@Gilad“临时浮点数”没有“指定的精度”,在某些情况下这种方法会失效。这个问题基本上就像问“什么是'%.2f'格式的等价物”?
user2864740 2015年

Answers:


131

一种典型的方法是使用stringstream

#include <iomanip>
#include <sstream>

double pi = 3.14159265359;
std::stringstream stream;
stream << std::fixed << std::setprecision(2) << pi;
std::string s = stream.str();

固定

使用固定的浮点表示法

floatfieldstr流的格式标志设置为fixed

floatfield设置为时fixed,浮点值使用定点表示法写入:该值用精确度字段precision)指定的十进制位数精确地表示,而没有指数部分。

setprecision


为了进行技术转换,例如将数据存储在XML或JSON文件中,C ++ 17定义了to_chars系列函数。

假设有一个兼容的编译器(在撰写本文时我们缺少此编译器),可以考虑这样的事情:

#include <array>
#include <charconv>

double pi = 3.14159265359;
std::array<char, 128> buffer;
auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), pi,
                               std::chars_format::fixed, 2);
if (ec == std::errc{}) {
    std::string s(buffer.data(), ptr);
    // ....
}
else {
    // error handling
}

28

进行此类操作的惯用方法是“打印到字符串”。在C ++中,这意味着要使用以下内容std::stringstream

std::stringstream ss;
ss << std::fixed << std::setprecision(2) << number;
std::string mystring = ss.str();

12

另一种选择是snprintf

double pi = 3.1415926;

std::string s(16, '\0');
auto written = std::snprintf(&s[0], s.size(), "%.2f", pi);
s.resize(written);

演示。应该添加错误处理,即检查written < 0


为什么snprintf在这种情况下会更好?请解释一下...它肯定不会更快,产生更少的代码[我编写了printf实现,它在2000行以下的代码中相当紧凑,但是宏扩展到2500行左右]
Mats Petersson

1
@MatsPetersson我坚信它将更快。这就是我首先做出此答案的原因。
哥伦布2015年

@MatsPetersson我已经执行了测量(GCC 4.8.1,-O2),这些结果表明snprintf确实花费的时间更少,仅为17/22倍。我将很快上传代码。
哥伦布2015年

@MatsPetersson我的基准测试可能有缺陷,但是在1000000次迭代(Clang 3.7.0,libstdc ++,-O2)下,stringstream版本花费的时间是snprintf版本的两倍。

我也做了一些测量-看来(至少在Linux上)stringstream和snprintf都使用相同的底层__printf_fp功能-奇怪的是,它花了这么长的时间stringstream,因为它实际上不是必须的。
Mats Petersson

9

您可以使用该fmt::format功能从{} FMT库

#include <fmt/core.h>

int main()
  std::string s = fmt::format("{:.2f}", 3.14159265359); // s == "3.14"
}

2精度在哪里。

已提出此格式化工具以在C ++:P0645中进行标准化。P0645和{fmt}都使用类似Python的格式字符串语法,该语法类似于的语法,printf{}用作而不是%


7

这里仅使用std的解决方案。但是,请注意,这仅舍入。

    float number = 3.14159;
    std::string num_text = std::to_string(number);
    std::string rounded = num_text.substr(0, num_text.find(".")+3);

对于rounded它产生:

3.14

该代码将整个浮点数转换为字符串,但是将所有字符都切成“。”后2个字符。


唯一的事情是,这样您实际上并没有舍入数字。
ChrCury78 '19

1
如我的回答中所述,@ ChrCury78仅四舍五入。如果要进行普通舍入,只需在值后面的diget中添加5。number + 0.005以我为例。
塞巴斯蒂安·R。

2

在这里,我提供一个否定的示例,您在将浮点数转换为字符串时要避免。

float num=99.463;
float tmp1=round(num*1000);
float tmp2=tmp1/1000;
cout << tmp1 << " " << tmp2 << " " << to_string(tmp2) << endl;

你得到

99463 99.463 99.462997

注意:num变量可以是接近99.463的任何值,您将获得相同的打印输出。关键是要避免方便的c ++ 11“ to_string”函数。我花了一段时间才摆脱这个陷阱。最好的方法是stringstream和sprintf方法(C语言)。C ++ 11或更高版本应提供第二个参数,即要显示的浮点之后的位数。现在的默认值为6。我认为这是为了使其他人不会浪费时间在此主题上。

我写了第一个版本,如果您发现任何需要修复的错误,请告诉我。您可以使用iomanipulator控制确切的行为。我的功能是显示小数点后的位数。

string ftos(float f, int nd) {
   ostringstream ostr;
   int tens = stoi("1" + string(nd, '0'));
   ostr << round(f*tens)/tens;
   return ostr.str();
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.