C++11 double转化为string
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及以上版本!
#include <string>
#include <cassert>
#include <iostream>
#include <sstream> std::string DoubleToStringByStdToString(double value)
{ const std::string& new_val = std::to_string(value);
return new_val;
}
▫
std::string DoubleToStringByStringStream(double value)
{
std::ostringstream stream;
stream << value;
return stream.str();
}
▫
void TestDoubleToStringByStdToString(const double value, const std::string& origin, const std::string& expect_str)
{
const std::string& val = DoubleToStringByStdToString(value);
std::cout << __FUNCTION__ << " --> original:" << origin
<< ", std::cout:" << value
<< ", std::to_string:" << val<< std::endl;
▫
assert( val == expect_str);
}
▫
void TestDoubleToStringByStringStream(const double value, const std::string& origin, const std::string& expect_str)
{
const std::string& val = DoubleToStringByStringStream(value);
std::cout << __FUNCTION__ << " --> original:" << origin
<< ", std::cout:" << value
<< ", std::stringstream:" << val<< std::endl;
▫
assert( val == expect_str);
} int main(int argc, char* argv[])
{
TestDoubleToStringByStdToString(, "", "0.000000");
TestDoubleToStringByStringStream(, "", ""); TestDoubleToStringByStdToString(., ".0", "0.000000");
TestDoubleToStringByStringStream(., ".0", ""); TestDoubleToStringByStdToString(0.0, "0.0", "0.000000");
TestDoubleToStringByStringStream(0.0, "0.0", ""); TestDoubleToStringByStdToString(1.0, "1.0", "1.000000");
TestDoubleToStringByStringStream(1.0, "1.0", ""); TestDoubleToStringByStdToString(1.0000008, "1.0000008", "1.000001");
TestDoubleToStringByStringStream(1.0000008, "1.0000008", ""); TestDoubleToStringByStdToString(1.0000000000001,"1.0000000000001", "1.000000");
TestDoubleToStringByStringStream(1.0000000000001,"1.0000000000001", ""); TestDoubleToStringByStdToString(0.0000000000001,"0.0000000000001", "0.000000");
TestDoubleToStringByStringStream(0.0000000000001,"0.0000000000001", "1e-13"); TestDoubleToStringByStdToString(0.12345678,"0.12345678", "0.123457");
TestDoubleToStringByStringStream(0.12345678,"0.12345678", "0.123457"); TestDoubleToStringByStdToString(100000000000.0000000000001,"100000000000.0000000000001", "100000000000.000000");
TestDoubleToStringByStringStream(100000000000.0000000000001,"100000000000.0000000000001", "1e+11"); TestDoubleToStringByStdToString(1e+,"1e+11", "100000000000.000000");
TestDoubleToStringByStringStream(1e+,"1e+11", "1e+11"); TestDoubleToStringByStdToString(123456.0000000000001, "123456.0000000000001", "123456.000000");
TestDoubleToStringByStringStream(123456.0000000000001, "123456.0000000000001", ""); TestDoubleToStringByStdToString(123456789.1234567,"123456789.1234567", "123456789.123457");
TestDoubleToStringByStringStream(123456789.1234567,"123456789.1234567", "1.23457e+08"); TestDoubleToStringByStdToString(123456789.0000000000001,"123456789.0000000000001", "123456789.000000");
TestDoubleToStringByStringStream(123456789.0000000000001,"123456789.0000000000001", "1.23457e+08"); return ;
}
我们这里将结果整理出来如下表
序号 | 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
第一版
std::string DoubleToString(const double value, unsigned int precision)
{
std::ostringstream out;
if (precision > )
out.precision(precision); out << value;
return out.str();
} int main(int argc, char* argv[])
{
std::cout << DoubleToString(., ) << std::endl;
std::cout << DoubleToString(0.0, ) << std::endl;
std::cout << DoubleToString(., ) << std::endl;
std::cout << DoubleToString(1.0, ) << std::endl;
std::cout << DoubleToString(, ) << std::endl;
std::cout << DoubleToString(0.12345, ) << std::endl;
std::cout << DoubleToString(0.12345678, ) << std::endl;
std::cout << DoubleToString(0.12345678, ) << std::endl;
std::cout << DoubleToString(0.12345678, ) << std::endl;
std::cout << DoubleToString(0.12345678, ) << std::endl;
return ;
}
这是测试结果的输出:
0
0
0
1
11234
0.12345
0.12345678
0.12345678
0.12345678
0.123457
第二版
多数情况下我们更加关注的是小数点后的几位数,所以我们调整参数控制小数点后位数。
#include <limits>
std::string DoubleToString(const double value, unsigned int precisionAfterPoint)
{
std::ostringstream out;
// 清除默认精度
out.precision(std::numeric_limits<double>::digits10);
out << value; std::string res = std::move(out.str());
auto pos = res.find('.');
if (pos == std::string::npos)
return res; auto splitLen = pos + + precisionAfterPoint;
if (res.size() <= splitLen)
return res; return res.substr(, splitLen);
} int main(int argc, char* argv[])
{
std::cout << DoubleToString(., ) << std::endl;
std::cout << DoubleToString(0.0, ) << std::endl;
std::cout << DoubleToString(., ) << std::endl;
std::cout << DoubleToString(1.0, ) << std::endl;
std::cout << DoubleToString(, ) << std::endl;
std::cout << DoubleToString(12345.12345678, ) << std::endl;
std::cout << DoubleToString(12345.12345678, ) << std::endl;
std::cout << DoubleToString(12345.12345678, ) << std::endl;
std::cout << DoubleToString(12345.12345678, ) << std::endl;
std::cout << DoubleToString(12345.12345678, ) << std::endl;
std::cout << DoubleToString(12345.00000001, ) << std::endl;
std::cout << DoubleToString(12345.00000001, ) << std::endl;
std::cout << DoubleToString(12345.00000001, ) << std::endl;
return ;
}
这是测试结果的输出:
0
0
0
1
11234
12345.12345678
12345.12345678
12345.1234567
12345.12345678
12345.123456
12345.0000000
12345.00000001
12345.000000
第三版
更进一步的,我们一般默认情况下小数点后是是6位小数的。所以我们可以设置默认参数:
#include <limits>
std::string DoubleToString(const double value, unsigned int precisionAfterPoint = )
{
std::ostringstream out;
// 清除默认精度
out.precision(std::numeric_limits<double>::digits10);
out << value; std::string res = std::move(out.str());
auto pos = res.find('.');
if (pos == std::string::npos)
return res; auto splitLen = pos + + precisionAfterPoint;
if (res.size() <= splitLen)
return res; return res.substr(, splitLen);
}
第四版
1:实际上第三版的实现存在一个BUG,即设置默认小数位后没有执行四舍五入!
2:性能。这个实现性能如何,是不是存在更佳的实现呢?
3:处理完成后,如果小数位全是0,该怎么处理?
请读者自己去研究解决。
C++11 double转化为string的更多相关文章
- Money类型转化为String去除小数点后0解决方法
Money类型转化为String去除小数点后0从数据库提取Money类型后,字符串如:1212.0000 如何使其成为1212 注:去掉了小数点 如果是:1212.0100 使 ...
- Java,double类型转换成String,String装换成double型
今天,老师布置了小系统,银行用户管理系统,突然发现自己的基础知识好薄弱,就把这些记录一下, double类型转化string:Double.toString(double doub); String类 ...
- Object 转化为String时的一个问题 null->"null"
近日在工作出了一个较大的问题,导致被客户投诉. 事情大致是,某个功能里新增对用户手机的修改,在平台数据同步过程中,出现了将用户以前的要同步的数据,那时还没有手机号码所以是null,新功能上线后,将手机 ...
- Java-集合=第五题 (Map)设计Account 对象如下: private long id; private double balance; private String password; 要求完善设计,使得该Account 对象能够自动分配id。 给定一个List 如下: List list = new ArrayList(); list.add(new A
第五题 (Map)设计Account 对象如下: private long id; private double balance; private String password; 要求完善设计,使得 ...
- mfc中CString转化为string的方法
LL(1)分析法实验的mfc做到最后因为CString转化为string的问题卡了一个多小时,也是惨,网上各种方法找过都不行.幸亏最后还是找到几行代码搞定了.特此mark一下. USES_CONVER ...
- 设计Account 对象如下: private long id; private double balance; private String password; 要求完善设计,使得该Account 对象能够自动分配id。 给定一个List 如下:
package homework005; public class Account { private long id; private double balance; private String ...
- 将fastjson元素转化为String[]
在fastjson中如果JSONObject中添加了 String[] 类型的元素 例如 JSONObject jo = new JSONObject(); String[] array = {&qu ...
- C++ double类型转string类型后,怎么实现小数点后只显示一个数字
C++ double类型转string类型后,怎么实现小数点后只显示一个数字 #include <iostream> #include <sstream> #include & ...
- java String转int int转化为String
String转int String str = "123"; int a = Integer.parseInt(str); System.out.println(a); Integ ...
随机推荐
- windows编程 进程的创建销毁和分析
Windows程序设计:进程 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,在Windows编程环境下,主要由两大元素组成: • 一个是操作系统用来管理进程的内核对象.操作系统使用内 ...
- Shodan的http.favicon.hash语法详解与使用技巧
在Shodan搜索中有一个关于网站icon图标的搜索语法,http.favicon.hash,我们可以使用这个语法来搜索出使用了同一icon图标的网站,不知道怎么用的朋友请参考我上一篇文章. 通过上一 ...
- [洛谷P1650] 田忌赛马
贪心难题:总结贪心问题的一般思路 传送门:$>here<$ 题意 田忌和齐王各有n匹马,赛马时一一对应.赢+200,输-200,平+0. 问最多多少钱? 数据范围:$n \leq 2000 ...
- 在中断服务函数中使用FreeRTOS系统延时函数vTaskDelay导致看门狗复位的情况
@2019-04-09 [问题] 控制程序工作一段时间异常重启 [分析] 经定位分析重启原因为看门狗复位导致 [解决] 经排查发现在中断服务函数中使用了FreeRTOS的系统时延函数vTaskDela ...
- 洛谷P3480 KAM-Pebbles
题目大意: 有N堆石子,除了第一堆外,每堆石子个数都不少于前一堆的石子个数.两人轮流操作每次操作可以从一堆石子中移走任意多石子,但是要保证操作后仍然满足初始时的条件.谁没有石子可移时输掉游戏.问先手是 ...
- C# webapi 上传下载图片
客户端上传文件 string url = url + "webUploadFile"; Uri server = new Uri(url); HttpClient httpClie ...
- python全栈开发中级班全程笔记(第二模块)第一部分:文件处理
第二模块 第一部分:文件处理与函数 #插曲之人丑就要多读书:读书能够提高个人素质与内涵,提升个人修养与能力,以及层次的提升. 推荐书籍:追风筝的人.白鹿原 电影:阿甘正传.辛德勒的名单 第一节:三 ...
- Redis-Cluster操作命令大全
今天整理下redis-cluster操作命令 一.Cluster操作命令 CLUSTER INFO 打印集群的信息 CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相 ...
- 分析web.xml
<?xml version="1.0" encoding="UTF-8"?> //xml的版本:1.0 和 编码:utf-8 <web-ap ...
- python 私有方法
最近了解到python私有方法的来由: Python中默认的成员函数,成员变量都是公开的(public),而且python中没有类似public,private等关键词来修饰成员函数,成员变量. 在p ...