Chinaunix首页 | 论坛 | 博客
  • 博客访问: 376628
  • 博文数量: 105
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 826
  • 用 户 组: 普通用户
  • 注册时间: 2013-02-16 13:58
个人简介

记录有意义的东西

文章分类

全部博文(105)

文章存档

2013年(105)

我的朋友

分类: C/C++

2013-08-23 10:36:47

       这里以C语言的浮点数为例,在IEEE浮点标准下,整数转换为浮点数的过程做一些直观的分析和具体的实现,IEEE浮点数的标准细节详见()。

 

        在C语言中,使用float和double类型数据分别对应单精度和双精度的浮点格式。以float为例,由于float是32位,int在32位机器上也是32位。因此,float必然不能对所有的int进行准确的表示。实际上,在数轴上,浮点数所能表示的数呈非均匀的分布。举例如下图。


 

                                         .     . -3  .   .  .  .-2  . . .  -1..........0.........1.. . .   . 2 .  .     .      3.       .

 

 

       图中的点代表float可表示的数,可以看出,在所能表示的数中,接近0的比较密集,远离0的则步长逐渐增大。具体的步长可以根据浮点数标准算出。

      以float为例,符号位1位,阶码8位,位数23位。由IEEE浮点的标准可知,非规格化数表示那些非常接近0.0的数。这时候,阶码域全为0.因此,非规格化数的步长为

                                                         2-23×2-127 ≈ 1.4×10-45

 

      而非规格化数的范围则约等于   -1.2×10-38 到1.2×10-38  在这个范围内,float能表示的数呈均匀分布。

       而int则处在规格化数的范围内。对于规格化数,步长不均匀。步长可表示为

 

                                                                         2-23×2E

        其中,E的取值范围是-126~+127。显然,随着E增大,步长增大。因此,对于越远离0的区域,步长越大。当E =  30时,步长为128。如下程序是一个验证。

                                  

 

 

         其中,浮点数表示230次方,刚阶码值E=30,程序中a数组记录x每次加一的结果,从输出中可以看出,因为步长为128,在0-64次相加中,并没有改变a[i]的值,而在后64次相加中,a[i]则保持为230次方+128

 

                                                                   

        因此,除了不均匀的步长以外,还需要考虑的是舍入的问题。由上面的测试中可知,C语言的舍入方法中,若整数处于步长的前半,则向下舍入,否则向上舍入。而对于刚好处于中间的数,例如上图中a[64],这种与前后的可取的数距离相等,则采用向偶数舍入的原则。即取表示成float形式后,最后一位为偶数(0)的数。

        分析到此,开始实现,说白的就是实现一个 float f = float(integer)的功能。函数原型如下:

                                                                       unsigned  float_itof(int i)  

      把整数i转换为float的表示形式,然后返回对应的4个字节。函数中不能使用float类型及其运算。

      代码如下:

                      

  1. unsigned float_i2f(int i)  
  2. {  
  3.     unsigned x,E,e;  
  4.     int count;  
  5.     unsigned j;  
  6.     unsigned low,high;  
  7.       
  8.     count = 0;  
  9.     x = 0;  
  10.     if(i==0)  
  11.         return x;  
  12.     //float不采用补码,正负数根据第一位符号位决定  
  13.     if(i<0)  
  14.     {  
  15.         i = -i;  
  16.         x = x|0x80000000;  
  17.     }     
  18.     j = i;  
  19.     //整数均为规格化数,先进行移位  
  20.     while((j&0x80000000)!=0x80000000)  
  21.     {  
  22.       j = j<<1;  
  23.       count++;  
  24.     }  
  25.     j=j<<1;  
  26.     //求出阶码  
  27.     E = 32-++count;  
  28.     e = E+127;  
  29.     //小于2的24次方,把阶码和有效位填入,完成  
  30.     if((i&0xff000000)==0)  
  31.     {    
  32.       x = x|(e<<23);  
  33.       x = x|(j>>9);  
  34.       return x;  
  35.     }  
  36.     //大于2的24次方,要进行舍入  
  37.     else   
  38.     {        
  39.       j=j>>count;  
  40.       //high low即进位或舍去尾数  
  41.       low = j&(~((1<<(E-23))-1));     
  42.       high = low+(1<<(E-23));  
  43.       //偶舍入原则  
  44.       if(j-low>high-j)  
  45.           j = high;  
  46.       else if(j-low
  47.           j = low;  
  48.       else if((low&(1<<(E-23)))==0)  
  49.           j = low;  
  50.       else   
  51.           j = high;  
  52.       if((((low>>(E-23))&0x7fffff)==0x7fffff) && (j==high))  
  53.       {  
  54.           e++;  
  55.       }  
  56.       //填入各位,完成  
  57.       x = x|(e<<23);  
  58.       x = x|((j>>(E-23))&0x7fffff);  
  59.     }  
  60. }  
 


        对输入i进行 INT_MIN 到 INT_MAX的范围测试,与float(i)的结果逐字节比较。代码正确。

阅读(16183) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~