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

此文发出后,有网友反映,我的回答不符合题意,即没有去实现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:
  1. bool IsNumber(char c)   
  2. {   
  3.     if('0'>c) return false;   
  4.     if('9'<c) return false;   
  5.     return true;   
  6. }   
  7. double stof(char* szFloatString)   
  8. {   
  9.     double fRet=0.0;    //试了一下,不能用float,精度太低了,我改用double   
  10.     double fRetLittleNumber=0.0;   
  11.     int nStringLength=strlen(szFloatString);   
  12.     int i=0;   
  13.     if(0>=nStringLength)   
  14.         goto stof_End_Process_Error;   
  15.     char cTarget=0;   
  16.   
  17.     i=0;                //这是在找整数部分   
  18.     //整数部分顺找,找到一个数字,基数*10+这个数字,就是把数字用10进制拼接到基数中   
  19.     while(1)           
  20.     {   
  21.         cTarget=*(szFloatString+i);   
  22.         if('.'==cTarget)   
  23.             goto stof_Get_Little_Number;   
  24.         if('\0'==cTarget)   
  25.             goto stof_End_Process;   
  26.         if(!IsNumber(cTarget))   
  27.             goto stof_End_Process_Error;   
  28.         cTarget-='0';   
  29.         fRet*=10.0;     //先*10   
  30.         fRet+=cTarget;  //再+,原来是1,新数字是2,1*10+2=12   
  31.         i++;   
  32.     }   
  33. stof_Get_Little_Number:     //这是在找小数部分   
  34.     //小数部分,从右向左逆找   
  35.     //找到新数字,基数+新数字/10,这是把新数字拼接到左边   
  36.     i=nStringLength-1;   
  37.     while(1)   
  38.     {   
  39.         cTarget=*(szFloatString+i);   
  40.         if('.'==cTarget)   
  41.             goto stof_I_Get_It;   
  42.         if(!IsNumber(cTarget))   
  43.             goto stof_End_Process_Error;   
  44.         cTarget-='0';   
  45.         fRetLittleNumber+=cTarget;  //先+新数字   
  46.         fRetLittleNumber/=10.0;     //再/10,0+1/10=0.1,0.1+2/10=0.21,明白没有?   
  47.         i--;   
  48.     }   
  49. stof_I_Get_It:          //找到了,拼接数字   
  50.     fRet+=fRetLittleNumber;   
  51.     goto stof_End_Process;   
  52. stof_End_Process_Error: //这是出错了   
  53.     printf("\"%s\" is not float!\n",szFloatString);   
  54.     fRet=0.0;   
  55. stof_End_Process:       //这是返回点   
  56.     return fRet;   
  57. }   
  58. void Test_stof(void)   
  59. {   
  60.     char* pStr="";   
  61.     pStr="123";   
  62.     printf("\"%s\"=%f\n",pStr,stof(pStr));   
  63.     pStr="123.321";   
  64.     printf("\"%s\"=%f\n",pStr,stof(pStr));   
  65.     pStr="1234567890.0987654321";   
  66.     printf("\"%s\"=%f\n",pStr,stof(pStr));   
  67. }   
最后的运行结果:
Code:
  1. "123"=123.000000   
  2. "123.321"=123.321000   
  3. "1234567890.0987654321"=1234567890.098765  
看见没,由于C编译器本身的精度问题,太长的小数被截短了。double还好点,要是float,第二个答案都是123.3209999,误差就太大了。
C语言准确地讲,不是一门太适合数学计算的语言,它浮点精度始终有限,如果要做纯正的数学计算,建议用Fortran等专业的数学计算语言。
当然,C++可以提出一些替代解决方案,比如说,我们自己做个类,里面用特殊的结构,比如就是超常数组来存储一个高精度浮点数的很多位,并提供输入输出方法,以及常用的数学计算方法,说白了,就是我们自己实现一个浮点数类,那可以把精度做得很高的,不过,这显然不是一篇博文能讲清楚的,有兴趣的朋友,可以自己试试。
另外,这个函数没有处理负数,这个题目我留给大家想吧,看懂了我的代码,加个负数支持也很容易。
好吧,第一个问题就回答在这里。
第六个还用回答吗?
sprintf(szBuffer,"%f",fResult);
直接用字符串输出函数输出到一个缓冲区就好了。
不过,为了安全起见,建议使用《0bug-C/C++商用工程之道》一书中的安全字符串构造函数,我这里给你个原型,这个是工程代码,我用了近十年都没出过错,可以直接用的。
Code:
  1. int SafePrintf(char* szBuf,int nMaxLength,char *szFormat, ...)   
  2. {   
  3.     int nListCount=0;   
  4.     va_list pArgList;   
  5.   
  6.     if (!szBuf) goto SafePrintf_END_PROCESS;   
  7.     va_start (pArgList,szFormat);   
  8.     nListCount+=Linux_Win_vsnprintf(szBuf+nListCount,   
  9.         nMaxLength-nListCount,szFormat,pArgList);   
  10.     va_end(pArgList);   
  11.     if(nListCount>(nMaxLength-1)) nListCount=nMaxLength-1;   
  12.     *(szBuf+nListCount)='\0';   
  13.   
  14. SafePrintf_END_PROCESS:   
  15.     return nListCount;   
  16. }   
 简单说,就是给出字符串缓冲区,还要给出一个缓冲区大小,我的函数保证不会打出去溢出,还有,就是不管缓冲区够不够,总之保证你最后得到一个'\0'的结束符。
你先看看吧,有问题再问。
肖舸
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值