【问题标题】:double to std::string with dynamic precisicion (without trailing zeros)具有动态精度的双重到 std::string (不带尾随零)
【发布时间】:2016-03-01 13:37:04
【问题描述】:

我想将double 值转换为std::string。目前在写

return std::to_string(double_value);

但这仅返回 7 位数字,因为内部 to_string() 仅使用 std::vsnprintf%f 格式说明符(另请参阅 here)。

我现在可以手动调用 std::vsnprintf 并使用 %.15f 作为格式说明符,但这会导致尾随零。

我(在我看来非常明显)现在的目标是采用这样的方法:

string o1 = to_string(3.14)
string o2 = to_string(3.1415926536)
assert(o1 == "3.14")
assert(o2 == "3.1415926536")

Here 很好地阐述了从%.20 输出中修剪尾随零,但这个答案大约有 8 年的历史。

也许事情发生了变化?我现在可以在 C++ 中将 double 转换为双精度而没有尾随零吗?

解决方案:

根据2mans 的回答,您可以编写这样的通用函数:

template<typename T>
inline std::string tostr(T value) {
    std::ostringstream s;
    s.precision(std::numeric_limits<T>::digits10);
    s << value;
    return s.str();
}

这将表现得像数字类型所期望的那样。请注意,我使用digits10 而不是max_digits10 来支持一个漂亮的十进制表示,而不是更多的数字和尾随..0000001

另外,恕我直言,值得添加 [v][s][n]printf() 以及格式字符串“%.15g”(而不是“f”)也会修剪尾随零(不适用于更多数字,因为它们不能用 64 位表示,这会导致尾随 '1' 之类的东西,例如 3.12 -> "3.1200000000000001")

还是很奇怪

也许有人可以告诉我为什么 std::to_string(double) 是用 C++-11 硬代码引入到 vsnprintf(..., "%f", ...) 而不是像 vsnprintf("%.15g") 这样会导致更精确的表示而不影响 C 代码的东西?

【问题讨论】:

  • C 的一个优点是它非常向后兼容。链接答案中的 C 代码已有 8 年历史并不重要,它仍然可以工作,并且与 C11 标准没有任何相关的变化。翻译成 C++ 也应该不难。没有这样的东西是不可能的,除非你事先知道有效数字的数量。
  • 八岁还是八小时都没关系:好的代码就是好的代码。 (另外,它是 C++……变化不大)。
  • 您打算如何处理浮点舍入?我尝试了一些简单的向字符串添加字符的方法,但3.14 可能不完全是3.14 存储在内存中。在不限制数字的情况下,您可以在需要 2.12 时获得 2.12000000005

标签: c++ string double


【解决方案1】:

您可以将字符串流(sstring)与流操纵器一起使用,请参见下面的示例:

  std::stringstream ss1;
  std::stringstream ss2;
  ss1.precision(15);    
  ss1 << 3.14;
  std::cout << ss1.str()<<' '<<("3.14" == ss1.str())<<std::endl;
  ss2.precision(15);
  ss2 << 3.1415926536;
  std::cout << ss2.str()<<' '<<("3.1415926536" == ss2.str())<<std::endl;

或者你可以使用 boost 格式。这里是a link

  std::cout<<format("%.2f") % 3.14 <<std::endl;
  std::cout<<format("%.10f") % 3.1415926536 <<std::endl;

【讨论】:

  • 在这个例子中你仍然需要手动指定精度。使用vsnprintf(),如果您不向%f 添加精度,则会正确修剪它,但它限制为7 位数。
  • 您可以将精度设置为 15。当您将流转换为字符串时,字符串末尾不会包含“0”。
  • 你是对的 - 你不能使用double 可以表示的十进制数字的最大数量(应该是 17)。 (见我的编辑)
猜你喜欢
  • 1970-01-01
  • 2013-02-18
  • 1970-01-01
  • 1970-01-01
  • 2012-12-21
  • 1970-01-01
  • 1970-01-01
  • 2014-02-02
  • 1970-01-01
相关资源
最近更新 更多