<b>C++中对浮点数的格局化显示</b>[VC/C++编程]
本文“<b>C++中对浮点数的格局化显示</b>[VC/C++编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
在很多利用程序范畴中,都需求掌握小数点后的小数位,但是浮点数对此不能供应直接的支持.怎样对程序中的浮点数据举行"整齐"地格局化呢?在此我们有一个迂回的办法,先把它们转换为字符串,格局化后以文本情势显示出来.
在平常编程中--包含对话框、关系数据库、金融程序、SMS程序及一切处理数据文件的程序,需求掌握小数点后的小数位的情形非常广泛,本文中将要讲授若何用简单的办法来掌握小数位,别的,还要揭开字符串及数据精度的一点点小奥秘.
问题的引出
若有一个函数,其可承受一个long double参数,并将参数转换为字符串,后果字符串应保存两位小数,比方,浮点值123.45678应当生成"123.45"这样的字符串.表面上看来这是一个意义不大的编程问题,但是,假如真要在实际中派上用场,函数应计划为具有一定弹性,以答应调用者指定小数位数.别的,函数也应当可以处理各种非常情形,如像123.0或123这样的整数.
在开始之前,先看一下编写"文雅"C++代码时的两句"真言":
"真言"1:无论什么时刻需求格局化一个数值,都应先转换为一个字符串.这样可保证每位数刚好占据一个字符.
"真言"2:在需求转换为字符串时,请利用<sstream>库.
转换函数的接口非常简便:第一个参数是需被格局化的数值;第二个参数代表小数点后显示的小数位,且应当具有一个默许值;返回值为一个string范例:
string do_fraction(long double value, int decplaces=3);
注意,第二个参数代表的小数位数中包含了小数点,因此,两位小数需求默许值为3.
精度问题
当然,第一步是把long double值转换为一个string,利用尺度C++库<sstream>简直是手到擒来.但是,有一件事情必须惹起注意,因为某些缘由,stringstream对象默许精度为6,而很多程序员错误地把"精度"理解为小数的位数,这是不精确的,精度应指代全部位数.因而,数字1234.56可安全地通过默许精度6来表示,但12345.67会被截断为12345.6.这样的话,假如你有一个非常大的数,如1234567.8,它的后果会静暗暗地转换为科学记数法:1.23457e+06,这明显不是我们想要的.为避免这样的麻烦,在开始转换之前,应把默许精度设为最大.
为得到long double能表示的最大位数,可以利用<limits>库:
string do_fraction(long double value, int decplaces=3)
{
int prec=numeric_limits<long double>::digits10; // 18
ostringstream out;
out.precision(prec);//覆盖默许精度
out<<value;
string str= out.str(); //从流中取出字符串 数值目前存储在str中,等候格局化.
小数点的位置
要举行格局化,首先要肯定小数点的位置,假如小数位多于decplaces,do_fraction()会删除多余的.
要定位小数位,可以利用string::find(),在STL算法中利用了一个常量来代表"数值未找到",在字符串中,这个常量为string::npos:
char DECIMAL_POINT='.'; // 欧洲用法为','
size_t n=str.find(DECIMAL_POINT);
if ((n!=string::npos)//能否有小数点呢?
{
//查抄小数的位数
}
假如没有小数点,函数直接返回字符串,不然,函数将持续查抄小数位能否多于decplaces.假如是,小数部份将会被截断:
size_t n=str.find(DECIMAL_POINT);
if ((n!=string::npos)//有小数点吗?
&&(str.size()> n+decplaces)) //背面至少还有decplaces位吗?
//在小数decplaces位之后写入nul
str[n+decplaces]='';
最后一行覆盖了多余的小数位,它利用了常量来截断字符串,要注意,string对象的数据可以包含nul字符;而字符串的实际长度由size()的返回值决意.因此,你不能假定字符串已被精确地格局化,换句话来说,假如在str中本来为"123.4567",在插入常量之后,它变成了"123.457",为把str缩减为"123.45",普通可以利用自交换的办法: str.swap(string(str.c_str()) );//删除nul之后的多余字符
那它的原理是什么呢?函数string::c_str()返回一个const char *代表此字符串对象,而这个值被用作一个暂时string对象的初始化值,接着,暂时对象又被用作str.swap()的参数,swap()会把值"123.45"赋给str.一些老一点的编译器不支持默许模板参数,大概不会让swap()通过编译,假如是这样的话,利用手工交换来替换:
string temp=str.c_str();
str=temp;
代码虽不是很"美好",但能到达目的就行.以下是do_fraction()的完好代码:
string do_fraction(long double value, int decplaces=3)
{
ostringstream out;
int prec=
numeric_limits<long double>::digits10; // 18
out.precision(prec);//覆盖默许精度
out<<value;
string str= out.str(); //从流中取出字符串
size_t n=str.find(DECIMAL_POINT);
if ((n!=string::npos) //有小数点吗?
&& (str.size()> n+decplaces)) //背面至少还有decplaces位吗?
{
str[n+decplaces]='';//覆盖第一个多余的数
}
str.swap(string(str.c_str()));//删除nul之后的多余字符
return str;
}
假如不想通过传值返回一个string对象,还可增添一个参数,把str对象以引用传送:
void do_fraction(long double value, string & str, int decplaces=3);
从个人的角度来说,还是偏向于让编译器做这样的优化,别的,利用传值返回,还可以让你以下面这种方法利用do_fraction():
cout << funct(123456789.69999001) << ' ' << funct(12.011)<<endl;
输出:
123456789.69 12.01
以上是“<b>C++中对浮点数的格局化显示</b>[VC/C++编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
本文地址: | 与您的QQ/BBS好友分享! |