使用动态精度加倍到 std::string(没有尾随零)
double to std::string with dynamic precisicion (without trailing zeros)
我想将 double
值转换为 std::string
。目前我正在写
return std::to_string(double_value);
但这只有 returns 7 位数字,因为在内部 to_string()
只是使用 std::vsnprintf
和 %f
格式说明符(另请参阅 here)。
我现在可以使用 %.15f
作为格式说明符手动调用 std::vsnprintf
,但这会导致尾随零。
我(在我眼里很明显)现在的目标是采用这样的方法:
string o1 = to_string(3.14)
string o2 = to_string(3.1415926536)
assert(o1 == "3.14")
assert(o2 == "3.1415926536")
Here 是对 trim 从 %.20
输出中提取尾随零的很好的阐述,但这个答案已有 8 年历史了。
也许情况发生了变化?我现在可以在 C++ 中转换没有尾随零的双精度 double
吗?
解法:
根据 2man 的回答,您可以编写如下通用函数:
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')也将 trim 尾随零(不能使用更多数字,因为它们不能用 64 位表示,这会导致尾随“1”之类的东西,例如 3.12 -> “3.1200000000000001”)
还是奇怪:
也许有人可以告诉我为什么用 C++-11 引入的 std::to_string(double)
硬编码为 vsnprintf(..., "%f", ...)
而不是像 vsnprintf("%.15g")
这样的东西,这样会导致更精确的表示不影响 C 代码?
您可以将字符串流 (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;
我想将 double
值转换为 std::string
。目前我正在写
return std::to_string(double_value);
但这只有 returns 7 位数字,因为在内部 to_string()
只是使用 std::vsnprintf
和 %f
格式说明符(另请参阅 here)。
我现在可以使用 %.15f
作为格式说明符手动调用 std::vsnprintf
,但这会导致尾随零。
我(在我眼里很明显)现在的目标是采用这样的方法:
string o1 = to_string(3.14)
string o2 = to_string(3.1415926536)
assert(o1 == "3.14")
assert(o2 == "3.1415926536")
Here 是对 trim 从 %.20
输出中提取尾随零的很好的阐述,但这个答案已有 8 年历史了。
也许情况发生了变化?我现在可以在 C++ 中转换没有尾随零的双精度 double
吗?
解法:
根据 2man 的回答,您可以编写如下通用函数:
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')也将 trim 尾随零(不能使用更多数字,因为它们不能用 64 位表示,这会导致尾随“1”之类的东西,例如 3.12 -> “3.1200000000000001”)
还是奇怪:
也许有人可以告诉我为什么用 C++-11 引入的 std::to_string(double)
硬编码为 vsnprintf(..., "%f", ...)
而不是像 vsnprintf("%.15g")
这样的东西,这样会导致更精确的表示不影响 C 代码?
您可以将字符串流 (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;