您的位置:首页 > 编程语言 > C语言/C++

关于浮点数和字符串转换的函数示例

2010-04-05 09:06 288 查看
此文发出后,有网友反映,我的回答不符合题意,即没有去实现Ieee754的表示法。
我又仔细看了一下原题,确实如此,看来自己马虎了,把题意理解错了,惭愧。
我下面的回答不算哈。
另外呢,如果这位同学询问的是IEEE754表示法的互相转换,我没有专门研究过这个,因此,这道问题我也不会,下列回答不算,欢迎有经验的网友另行撰文写出答案,我也跟着学习一下哈。
嗯,我正式向这位同学道歉。对不住了。

肖舸敬上

这是一位同学发到我邮箱的问题,看起来这位同学很急,不但发了邮件,还几次短消息催我,呵呵,那我回答一下。
嗯,这里还是先说明一下,我一般不太愿意在博文中回答具体程序问题,因为C和C++语言,太灵活了,一个问题,有一万种解法,另外,每种解法各有其适用面,贸然在博文中回答,必然不是很精确,回答效果不好。
这次呢,我看这位同学比较急迫,我就破个例,不过,正确的做法,我建议大家以后有了具体的程序问题呢,还是到课堂提问,大家来回答。那么多个脑袋,总比我一个脑袋聪明,想问题也全面,回答效果会比较好哈。
另外,这个程序我是为了回答问题,临时写出来的测试代码,不是工程代码,大家看看,理解意思就好了,不要贸然代入自己的工程,我不保证它是不是绝对没有bug的。它甚至不符合我《0bug-C/C++商用工程之道》里面的无错化程序思想。仅仅用来说明意思的哈,别被误导了。
原文如下:
我是浙江大学软件工程的,csdn上一直浏览您的主页。以前我只重理论,导致编程不行,现在开始狂编,我现在能问您个问题吗,纠结了好久了……
用C语言模拟计算机浮点数运算
1、float stof(char *); //十进制字符串 --> float  (如:"-1.0" --> 0xFF800000)
2、float fadd(float, float);
3、float fsub(float, float);
4、float fmul(float, float);
5、float fdiv(float, float);
6、void ftos(char *, float); //float --> 十进制字符串(如:0x40000000 --> "2.0")

而我就卡在第一和第六个函数上,我搜遍了网上的资料,搞了好几天没有搞出来,我搜到Ieee754的算法又不知道怎么去运用,我大概可以想到把它小数整数分开都做整数处理,但是感觉还是很难以下手……你能写个大概让我看一下吗,我主要就是第一和第六个函数存在问题,好纠结啊……
我的回答:
嗯,这位同学你好,你的第一个和第六个问题,我来试着回答一下。先说啊,这不是工程代码,是我为了给你回答问题临时写出来的测试代码,你看看好了,学会了思想自己写,我不保证其正确性的。

Code:

bool IsNumber(char c)
{
if('0'>c) return false;
if('9'<c) return false;
return true;
}
double stof(char* szFloatString)
{
double fRet=0.0; //试了一下,不能用float,精度太低了,我改用double
double fRetLittleNumber=0.0;
int nStringLength=strlen(szFloatString);
int i=0;
if(0>=nStringLength)
goto stof_End_Process_Error;
char cTarget=0;

i=0; //这是在找整数部分
//整数部分顺找,找到一个数字,基数*10+这个数字,就是把数字用10进制拼接到基数中
while(1)
{
cTarget=*(szFloatString+i);
if('.'==cTarget)
goto stof_Get_Little_Number;
if('\0'==cTarget)
goto stof_End_Process;
if(!IsNumber(cTarget))
goto stof_End_Process_Error;
cTarget-='0';
fRet*=10.0; //先*10
fRet+=cTarget; //再+,原来是1,新数字是2,1*10+2=12
i++;
}
stof_Get_Little_Number: //这是在找小数部分
//小数部分,从右向左逆找
//找到新数字,基数+新数字/10,这是把新数字拼接到左边
i=nStringLength-1;
while(1)
{
cTarget=*(szFloatString+i);
if('.'==cTarget)
goto stof_I_Get_It;
if(!IsNumber(cTarget))
goto stof_End_Process_Error;
cTarget-='0';
fRetLittleNumber+=cTarget; //先+新数字
fRetLittleNumber/=10.0; //再/10,0+1/10=0.1,0.1+2/10=0.21,明白没有?
i--;
}
stof_I_Get_It: //找到了,拼接数字
fRet+=fRetLittleNumber;
goto stof_End_Process;
stof_End_Process_Error: //这是出错了
printf("\"%s\" is not float!\n",szFloatString);
fRet=0.0;
stof_End_Process: //这是返回点
return fRet;
}
void Test_stof(void)
{
char* pStr="";
pStr="123";
printf("\"%s\"=%f\n",pStr,stof(pStr));
pStr="123.321";
printf("\"%s\"=%f\n",pStr,stof(pStr));
pStr="1234567890.0987654321";
printf("\"%s\"=%f\n",pStr,stof(pStr));
}

最后的运行结果:

Code:

"123"=123.000000
"123.321"=123.321000
"1234567890.0987654321"=1234567890.098765

看见没,由于C编译器本身的精度问题,太长的小数被截短了。double还好点,要是float,第二个答案都是123.3209999,误差就太大了。
C语言准确地讲,不是一门太适合数学计算的语言,它浮点精度始终有限,如果要做纯正的数学计算,建议用Fortran等专业的数学计算语言。
当然,C++可以提出一些替代解决方案,比如说,我们自己做个类,里面用特殊的结构,比如就是超常数组来存储一个高精度浮点数的很多位,并提供输入输出方法,以及常用的数学计算方法,说白了,就是我们自己实现一个浮点数类,那可以把精度做得很高的,不过,这显然不是一篇博文能讲清楚的,有兴趣的朋友,可以自己试试。
另外,这个函数没有处理负数,这个题目我留给大家想吧,看懂了我的代码,加个负数支持也很容易。
好吧,第一个问题就回答在这里。
第六个还用回答吗?
sprintf(szBuffer,"%f",fResult);
直接用字符串输出函数输出到一个缓冲区就好了。
不过,为了安全起见,建议使用《0bug-C/C++商用工程之道》一书中的安全字符串构造函数,我这里给你个原型,这个是工程代码,我用了近十年都没出过错,可以直接用的。

Code:

int SafePrintf(char* szBuf,int nMaxLength,char *szFormat, ...)
{
int nListCount=0;
va_list pArgList;

if (!szBuf) goto SafePrintf_END_PROCESS;
va_start (pArgList,szFormat);
nListCount+=Linux_Win_vsnprintf(szBuf+nListCount,
nMaxLength-nListCount,szFormat,pArgList);
va_end(pArgList);
if(nListCount>(nMaxLength-1)) nListCount=nMaxLength-1;
*(szBuf+nListCount)='\0';

SafePrintf_END_PROCESS:
return nListCount;
}

简单说,就是给出字符串缓冲区,还要给出一个缓冲区大小,我的函数保证不会打出去溢出,还有,就是不管缓冲区够不够,总之保证你最后得到一个'\0'的结束符。
你先看看吧,有问题再问。
=======================================================
在线底价购买《0bug-C/C++商用工程之道》
(直接点击下面链接或拷贝到浏览器地址栏)
http://s.click.taobao.com/t_3?&p=mm_13866629_0_0&n=23&l=http%3A%2F%2Fsearch8.taobao.com%2Fbrowse%2F0%2Fn-g%2Corvv64tborsvwmjvgawdkmbqgboq---g%2Cgaqge5lhebbs6qzlfmqmttgtyo42jm6m22xllqa-------------1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20---40--coefp-0-all-0.htm%3Fpid%3Dmm_13866629_0_0
肖舸
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息