首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

高效严谨的浮点数四舍五入的方法

2012-04-14 
求一个高效严谨的浮点数四舍五入的方法如题。自己写了2个,都不是很满意。参数d是要转换的数,p是保留到小数点

求一个高效严谨的浮点数四舍五入的方法
如题。自己写了2个,都不是很满意。
参数d是要转换的数,p是保留到小数点后的位数:

第一个:

C/C++ code
double round(double d,unsigned p){    if(d==0.0)        return 0.0;    double n=10;    for(;p>0;p--)        n*=10;    if(d>0.0)        return (long)(d*n+5) / 10 / (n/10);    else        return (long)(d*n-5) / 10 / (n/10);}

这方法由于int比double范围小很多,需要超过9位的小数就不适用了。很不严谨。

第二个:
C/C++ code
double round(double d,unsigned p){    //先转成字符串    char s[20];    sprintf(s,"%.*f",p,d);    //再转成double    char*sp=s;    bool neg_flag=false;    double res=0;    int x=0,y=1;    if(sp[0] == '+' || sp[0] == '-')        neg_flag = (*sp++ != '+');    while(isdigit(*sp))        res = res * 10 + (*sp++ - '0');    if(*sp++=='.')    {        while(isdigit(*sp))        {            x = x * 10 + (*sp++ - '0');            y*=10;        }        res+=x*1.0/y;    }    return neg_flag ? -res : res;}

这个个人觉得效率是不是偏低了点,而且p只能是是一位数的,大于10结果就完全不对。

求下一种更好的方法


[解决办法]
探讨
double round(double d,unsigned p)
{
char chs[10],data[200]
sprintf(chs,"%%.%uf",p);
sprintf(data,chs,d);
return atof(data);
}
我用TC2.0编译发现sprintf自己四舍五入了,怀疑不同编译器情况不一样.
如果sprintf不会四舍五入的话,加上下面一段;
……

[解决办法]
浮点数不精确,所以不存在严谨的做法。
[解决办法]
http://wenku.baidu.com/view/7c7e79f7ba0d4a7302763a94.html

//小数点后1位4舍5入,没处理负数。

floatround(float f){
__int32*p=(__int32*)&f;

//是否负数,负数的舍入逻辑是否和正数一样?
boolsign=false;

if(*p&0x80000000)
sign=true;
__int32exp=(*p& (~0x80000000))>>23;
exp-=127;

if(exp>=23)//没有小数部分
returnf;

__int32num=(1<<23)|(*p&0x7fffff);

//num为定点数。
//1.xxxx * 2^exp
if(exp>=0){
//小数点后1位位置 1<<(22-exp)
int shift=22-exp;
if(num&(1<<shift)){
num+=(1<<shift);
num&=-1<<shift;
if(num&(1<<24)){
num>>=1;//定点数部分/2
++exp;//exp+1
}
}else{
//截断小数
num&=~(1<<shift);
}
exp+=127;
*p=(exp<<23)|(num&0x7fffff);
returnf;
}else{
intshift=22-exp;
if(shift>23){//小于0.5
return0.0f;
}
++exp;
exp+=127;
*p=(exp<<23);
returnf;
}
}



[解决办法]
实现么……翻标准库实现去吧。不过搞不好是硬件直接实现的(否则C标准库搞这么一大堆接口就没太大意义了……)。
<cmath>

std::round
std::lround
std::llround
std::rint
std::lrint
std::llrint

<cfenv>
std::fegetround
std::fesetround

[解决办法]
无论低效高效都会入舍不准!

热点排行