浮点数在内存中的表示形式及浮点数比较

1 . 浮点数在内存中的表示形式

     首先说一下原,反,补,移码。移码其实就等于补码,只是符号相反。对于正数而言,原,反,补码都一样。对负数而言,反码除符号位外,在原码的基础上按位取反;补码则在反码的基础之上,在其最低位上加1;要求移码时,仍然是先求补码,再改符号。浮点数分为float和double,分别占4,8个字节,即32,64位。仅以32位的float为例,并附带说double。
在IEEE754标准中,规定,float的32位这样分:    符号位(S)  1 位;阶码(E) 8 位 ;尾数(M) 23 位。

     这里应该注意三点:  
          A, 阶码是用移码表示的,这里会有一个127的偏移量,它的127相当于0,小于127时为负,大于127时为,  如:10000001表示指数为129-127=2,表示真值为2^2,而01111110则表示2^(-1).
          B, 尾数全都是小数点后面的数,
          C, 尾数中省略了一个1,因此尾数全为0时,也是1.0...00;
     接下来只要说明几个问题就明白了,以123.456为例,表示为二进制就是:N (2) = 1111011. 01110100101111001 ,这里,会右移6位,得到N (2) = 1.111011 01110100101111001*2^6; 这种形式就可以用于上图中的表示格式了:

                       符号位(S) 0 ;阶码(E) 00000110 ;尾数(M) 11101101110100101111001

     阶码移码后: 符号位(S) 0 ;阶码(E) 10000101 ;尾数(M) 11101101110100101111001

                 即:0x42f6e979

在内存中的存储(大端):                                             

                  0x00000001 --> 79

                  0x00000002 --> e9

                  0x00000003 --> f6

                  0x00000004 --> 42

2. 浮点数的精度问题

    由于在将十进制转为二进制的过程中,常常不能正好转得相等,(当然,像4.0这样的就不会有损失,而1.0/3.0这样的必然损失),所以就产生了浮点数的精度问题。实际上,小数点后的23位二进制数,能影响的十进制数的前8位。

     这是为什么呢? 其实很简单,在上面表示的尾数中,是二进制的,小数点后有23位,最后一位的值为1时,它就是1/2^22=0.000000238实际取的时候肯定是0.0000002。也就是说,对于一个float型的浮点数,其有效的位数是从左到右数7位(包括缺省的1才是7位),当到达上面这个第8位时,就不可靠了。

     因此将上面的N (2) = 1.111011 01110100101111001*2^6;再转回十进制数时,很可能已经不再是123.456了。 

3. 浮点数的比较

     为什么浮点数不能直接作“等值比较”? 浮点数的精度问题!

     引用林锐《高质量C/C++代码编写指南》的一段话:

 【规则4-3-3】不可将浮点变量用“==”或“!=”与任何数字比较。无论float还是double类型的变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。假设浮点变量的名字为x,应当将:

               if (x == 0.0) // 隐含错误的比较
               转化为 :
               if ((x>=-EPSINON) && (x<=EPSINON))
               其中EPSINON是允许的误差(即精度)。

     关于EPSINON,可不是能随便定义的!而且应该能想到,double和float的EPSINON是不同的。定义成什么呢?不必你去定义了,ANSI C已经定义了这些常量:
               #include <float.h>
               FLT_EPSILON
               DBL_EPSILON
               LDBL_EPSILON

最后,看一个例子。

#include <stdio.h>
#include <stdlib.h>

main()
{

    float f1,f2 ,f3 f4;
    double d1, d2, d3, d4;
    d1 = 194268.02;
    d2 = 194268;
    d4 = 0.02;

    f1 = 194268.02;
    f2 = 194268;
    f4 = 0.02;

     printf("%f %f %f",f1,f2,f4); //输出--->194268.015625 194268.000000 0.020000

     printf("%f %f %f",f1,f2,f4); //输出--->194268.020000 194268.000000 0.020000

     printf("%f %f",d1-d2,d4);   //输出---> 0.020000 0.020000

     printf("%f %f",f1-f2,f4);     //输出---> 0.015625 0.020000

     if(d1-d2==d4)      ////输出---> !=

          printf("==");

     else

          printf("!=");

     if(d1-d2==d4)       ////输出---> !=

          printf("==");

     else

          printf("!=");

  }


 

 

 

 

 

 

 

 

 

 

posted on 2009-01-12 18:15  Hevcer  阅读(2138)  评论(0编辑  收藏  举报