博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++11 double转化为string
阅读量:5791 次
发布时间:2019-06-18

本文共 9578 字,大约阅读时间需要 31 分钟。

C++11转化double为string是一件很容易的事情。

 

方法:

1:使用C中的sprintf函数,这里就不说了。

2:使用std::ostringstream。这个与std::cout是一样的。这个在C++11以前就已经支持了的。这个得出的结果与使用std::cout的结果是一样的。

3:从C++11开始,标准库提供了std::to_string辅助函数转化各类型为一个字符串。

 

std::ostringstream和std::to_string

但是std::ostringstream和std::to_string使用的结果就有些很奇怪的差异了。主要有:

1:std::string得到的结果始终是小数位必然是6!

2:默认情况下,std::ostringstream对double使用的是6位精度。这里精度值的是整数位和小数位个数和。但是精度是可以设置的。这里统一谈论默认的情况。

也就是说,如果参数精度超过6位的话,那么会将数值四舍五入,然后丢弃多余的位数!

具体来说是这样的:

1:如果整数位不足6位,而整体精度超过了6,那么小数位四舍五入,然后截断多余的位数。

2:如果是整数位超过了6,那么舍弃小数位,然后按照科学计数法保存。

比如:

序号 double原值 std::ostringstream结果
1 1.0000000000001 1
2 0.12345678 0.123457
3 123456789.0000000000001 1.23457e+08
4 123456789.1234567 1.23457e+08
5 0.0000000000001 1e-13

 

 

 

 

 

 

 

 

 

下面我们详细比较std::ostringstream和std::to_string使用的结果的差异。

这里是详细的测试代码,请注意,这里必须是C++11及以上版本!

1     1 #include 
2 2 #include
3 3 #include
4 4 #include
5 5 6 6 std::string DoubleToStringByStdToString(double value) 7 7 { 8 9 8 const std::string& new_val = std::to_string(value);10 9 return new_val;11 10 }12 11 ▫13 12 std::string DoubleToStringByStringStream(double value)14 13 {15 14 std::ostringstream stream;16 15 stream << value;17 16 return stream.str();18 17 }19 18 ▫20 19 void TestDoubleToStringByStdToString(const double value, const std::string& origin, const std::string& expect_str)21 20 {22 21 const std::string& val = DoubleToStringByStdToString(value);23 22 std::cout << __FUNCTION__ << " --> original:" << origin24 23 << ", std::cout:" << value25 24 << ", std::to_string:" << val<< std::endl;26 25 ▫27 26 assert( val == expect_str);28 27 }29 28 ▫30 29 void TestDoubleToStringByStringStream(const double value, const std::string& origin, const std::string& expect_str)31 30 {32 31 const std::string& val = DoubleToStringByStringStream(value);33 32 std::cout << __FUNCTION__ << " --> original:" << origin34 33 << ", std::cout:" << value35 34 << ", std::stringstream:" << val<< std::endl;36 35 ▫37 36 assert( val == expect_str);38 37 }39 3840 39 int main(int argc, char* argv[])41 40 {42 41 TestDoubleToStringByStdToString(0, "0", "0.000000");43 42 TestDoubleToStringByStringStream(0, "0", "0");44 4345 44 TestDoubleToStringByStdToString(.0, ".0", "0.000000");46 45 TestDoubleToStringByStringStream(.0, ".0", "0");47 4648 47 TestDoubleToStringByStdToString(0.0, "0.0", "0.000000");49 48 TestDoubleToStringByStringStream(0.0, "0.0", "0");50 4951 50 TestDoubleToStringByStdToString(1.0, "1.0", "1.000000");52 51 TestDoubleToStringByStringStream(1.0, "1.0", "1");53 5254 53 TestDoubleToStringByStdToString(1.0000008, "1.0000008", "1.000001");55 54 TestDoubleToStringByStringStream(1.0000008, "1.0000008", "1");56 5557 56 TestDoubleToStringByStdToString(1.0000000000001,"1.0000000000001", "1.000000");58 57 TestDoubleToStringByStringStream(1.0000000000001,"1.0000000000001", "1");59 5860 59 TestDoubleToStringByStdToString(0.0000000000001,"0.0000000000001", "0.000000");61 60 TestDoubleToStringByStringStream(0.0000000000001,"0.0000000000001", "1e-13");62 6163 62 TestDoubleToStringByStdToString(0.12345678,"0.12345678", "0.123457");64 63 TestDoubleToStringByStringStream(0.12345678,"0.12345678", "0.123457");65 6466 65 TestDoubleToStringByStdToString(100000000000.0000000000001,"100000000000.0000000000001", "100000000000.000000");67 66 TestDoubleToStringByStringStream(100000000000.0000000000001,"100000000000.0000000000001", "1e+11");68 6769 68 TestDoubleToStringByStdToString(1e+11,"1e+11", "100000000000.000000");70 69 TestDoubleToStringByStringStream(1e+11,"1e+11", "1e+11");71 7072 71 TestDoubleToStringByStdToString(123456.0000000000001, "123456.0000000000001", "123456.000000");73 72 TestDoubleToStringByStringStream(123456.0000000000001, "123456.0000000000001", "123456");74 7375 74 TestDoubleToStringByStdToString(123456789.1234567,"123456789.1234567", "123456789.123457");76 75 TestDoubleToStringByStringStream(123456789.1234567,"123456789.1234567", "1.23457e+08");77 7678 77 TestDoubleToStringByStdToString(123456789.0000000000001,"123456789.0000000000001", "123456789.000000");79 78 TestDoubleToStringByStringStream(123456789.0000000000001,"123456789.0000000000001", "1.23457e+08");80 7981 80 return 0;82 81 }
View Code

 

我们这里将结果整理出来如下表

序号 double原值 std::cout std::ostringstream结果 std::to_string()结果
1 0 0 0 0.000000
2 .0 0 0 0.000000
3 0.0 0 0 0.000000
4 1.0 1 1 1.000000
5 1.0000008 1 1 1.000001
6 1.0000000000001 1 1 1.000000
7 0.0000000000001 1e-13 1e-13 0.000000
8 0.12345678 0.123457 0.123457 0.123457
9 100000000000.0000000000001 1e+11 1e+11 100000000000.000000
10 1e+11 1e+11 1e+11 100000000000.000000
11 123456.0000000000001 123456 123456 123456.000000
12 123456789.1234567 1.23457e+08 1.23457e+08 123456789.123457
13 123456789.0000000000001 1.23457e+08 1.23457e+08 123456789.000000

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

从上面的结果我们还可以发现一个关于std::to_string的特点

如果传入的double本身是科学记数法,to_string仍然可以执行转化,且得出的结果与该科学技术法表述的值转化的结果是一样的!

 

总结

虽然C++对关转化double为string提供的方法很多,但是的得出的结果不一样。所以在使用时应该统一方法,并且格外小心,如果是在对double很敏感的行业,那么应该对该操作封装,并提供足够的控制参数。

 

一种可参考的实现

从上面我们可以看出使用ostringstream或者to_string的方法,要么存在精度显示问题要么调整为科学计数法显示。这些都不是我们想要的。

所以我们可以使用ostringstream封装一个辅助函数,可以控制精度也可以控制科学计数法显示。

 

精度

ostringstream是可以控制精度的,函数原型如下:

std::ios_base::precision

 

第一版

1 std::string DoubleToString(const double value, unsigned int precision)                                                                                                                                                                                                           2 { 3    std::ostringstream out; 4    if (precision > 0) 5        out.precision(precision); 6  7    out << value; 8    return out.str(); 9 }10 11 12 int main(int argc, char* argv[])13 {14     std::cout << DoubleToString(0., 12) << std::endl;15     std::cout << DoubleToString(0.0, 12) << std::endl;16     std::cout << DoubleToString(.0, 12) << std::endl;17     std::cout << DoubleToString(1.0, 12) << std::endl;18     std::cout << DoubleToString(11234, 12) << std::endl;19     std::cout << DoubleToString(0.12345, 12) << std::endl;20     std::cout << DoubleToString(0.12345678, 12) << std::endl;21     std::cout << DoubleToString(0.12345678, 9) << std::endl;22     std::cout << DoubleToString(0.12345678, 8) << std::endl;23     std::cout << DoubleToString(0.12345678, 6) << std::endl;24     return 0;25 }
View Code

这是测试结果的输出:

0

0
0
1
11234
0.12345
0.12345678
0.12345678
0.12345678
0.123457

 

第二版

多数情况下我们更加关注的是小数点后的几位数,所以我们调整参数控制小数点后位数。

1 #include 
2 std::string DoubleToString(const double value, unsigned int precisionAfterPoint) 3 { 4 std::ostringstream out; 5 // 清除默认精度 6 out.precision(std::numeric_limits
::digits10); 7 out << value; 8 9 std::string res = std::move(out.str());10 auto pos = res.find('.');11 if (pos == std::string::npos)12 return res;13 14 auto splitLen = pos + 1 + precisionAfterPoint;15 if (res.size() <= splitLen)16 return res;17 18 return res.substr(0, splitLen);19 }20 21 int main(int argc, char* argv[])22 {23 std::cout << DoubleToString(0., 12) << std::endl;24 std::cout << DoubleToString(0.0, 12) << std::endl;25 std::cout << DoubleToString(.0, 12) << std::endl;26 std::cout << DoubleToString(1.0, 12) << std::endl;27 std::cout << DoubleToString(11234, 12) << std::endl;28 std::cout << DoubleToString(12345.12345678, 12) << std::endl;29 std::cout << DoubleToString(12345.12345678, 9) << std::endl;30 std::cout << DoubleToString(12345.12345678, 7) << std::endl;31 std::cout << DoubleToString(12345.12345678, 8) << std::endl;32 std::cout << DoubleToString(12345.12345678, 6) << std::endl;33 std::cout << DoubleToString(12345.00000001, 7) << std::endl;34 std::cout << DoubleToString(12345.00000001, 8) << std::endl;35 std::cout << DoubleToString(12345.00000001, 6) << std::endl;36 return 0;37 }
View Code

这是测试结果的输出:

0

0
0
1
11234
12345.12345678
12345.12345678
12345.1234567
12345.12345678
12345.123456
12345.0000000
12345.00000001
12345.000000

 

第三版

更进一步的,我们一般默认情况下小数点后是是6位小数的。所以我们可以设置默认参数:

1 #include 
2 std::string DoubleToString(const double value, unsigned int precisionAfterPoint = 6) 3 { 4 std::ostringstream out; 5 // 清除默认精度 6 out.precision(std::numeric_limits
::digits10); 7 out << value; 8 9 std::string res = std::move(out.str());10 auto pos = res.find('.');11 if (pos == std::string::npos)12 return res;13 14 auto splitLen = pos + 1 + precisionAfterPoint;15 if (res.size() <= splitLen)16 return res;17 18 return res.substr(0, splitLen);19 }
View Code

 

第四版

1:实际上第三版的实现存在一个BUG,即设置默认小数位后没有执行四舍五入!

2:性能。这个实现性能如何,是不是存在更佳的实现呢?

3:处理完成后,如果小数位全是0,该怎么处理?

请读者自己去研究解决。

转载于:https://www.cnblogs.com/chorulex/p/7660187.html

你可能感兴趣的文章
python的图形模块PIL小记
查看>>
shell变量子串
查看>>
iOS的主要框架介绍 (转载)
查看>>
react报错this.setState is not a function
查看>>
poj 1183
查看>>
从根本解决跨域(nginx部署解决方案)
查看>>
javascript实现的一个信息提示的小功能/
查看>>
Centos7.x:开机启动服务的配置和管理
查看>>
HTML5 浏览器返回按钮/手机返回按钮事件监听
查看>>
xss
查看>>
iOS:百度长语音识别具体的封装:识别、播放、进度刷新
查看>>
JS获取服务器时间并且计算距离当前指定时间差的函数
查看>>
华为硬件工程师笔试题
查看>>
jquery居中窗口-页面加载直接居中
查看>>
cd及目录快速切换
查看>>
Unity Shaders and Effects Cookbook (3-5) 金属软高光
查看>>
31-hadoop-hbase-mapreduce操作hbase
查看>>
C++ 代码风格准则:POD
查看>>
linux-友好显示文件大小
查看>>
【转】【WPF】WPF中MeasureOverride ArrangeOverride 的理解
查看>>