九月鹰飞

慎独自修,忠恕宽容,至诚尽性。

  VC知识库BLOG :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 登录 ::
  19 随笔 :: 13 文章 :: 158 评论 :: 3 Trackbacks
<2008年11月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

留言簿(6)

随笔分类

随笔档案

文章分类

文章档案

相册

搜索

最新评论

阅读排行榜

评论排行榜

<PRE>

// 经常看到坛友关于浮点数存储格式的讨论,不免心血来潮,编写一个小的测试程序
// 验证一下 Intel80x87 (符合IEEE浮点格式标准)下面的数据存储格式,以及转换
// 算法,也算加深一下自己的认识

#include <stdio.h>
#include <math.h>

typedef union
{
 float f;
 unsigned int i;
}FloatAndInt;

typedef struct tagTwoInt
{
 unsigned int i1;
 unsigned int i2;
}TwoInt;
typedef union
{
 double d;
 TwoInt ti;
}DoubleAndInt;

//计算尾数(二进制小数)的函数
double GetX(unsigned int w)
{
 //首先清除前面的9位
 w &=0x007FFFFF;

 //位掩码
 int bit = 0x00400000;

 //结果
 double value = 0;

 //位数据
 double d = 0.5;
 for(int i=0;i<23;i++)
 {
  if(w&bit)
  {
   value += d;
  }
  d = d/2.; //每次除2,属于二进制小数算法
  bit = bit>>1;
 }
 return value;
}

void main()
{
 FloatAndInt fi;
 fi.f = (float)1;
 printf("%x\n",fi.i);
 //output: 3f800000
 //        0011 1111  1000 0000  0000 0000  0000 0000
 //        ~ ~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //       符号位 8位指数 尾数(有效数字)是23位
 //
 // 符号位 0: 表示正数, 1:表示负数
 //  指数8位,01111111 = 127,减去偏移基数127等于0
 //  尾数23位,每一位表示2的负x次方,x= 1 ->23
 //  因此,浮点数到整数的计算方法是
 //  令
 //  s = 符号值 0或者1
 //  指数 e
 //  尾数 x: 二进制小数,函数GetX给出了计算方法
 //  iValue  = (-1)^s * (1+x)* 2^(e - 127)

 DoubleAndInt di;
 di.d = 1;
 printf("Size of Double is : %d \n",sizeof(DoubleAndInt));

 printf("%x,%x\n",di.ti.i1,di.ti.i2);
 //output: 0,3ff00000
 //由于低字节在前面,所以前面的32位(i1)都是0,这个1.5在内存中是
 //     3f f0 00 00 00 00 00 00
 //
 //所以双精度数据的格式是
 //     0011 1111 1111 0000 00000000 00000000 00000000 00000000 00000000 00000000
 //     ~ ~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //   符号位 11位指数  52位尾数
 //
 //指数偏移基址为011 1111 1111 = 1023
 //所以它的计算公式是
 //  
 //   iValue = (-1)^s  +  ( 1 + x ) * 2^(e - 1023);

 //测试1
 //下面针对float做一下验证
 FloatAndInt Testfi;
 Testfi.i = 0x41800000; //注意低位在前!
 //i = 0100 0001 1000 0000 0000 0000 0000 0000
 int s = (Testfi.i & 0x80000000)>>31;
 int e = (Testfi.i & 0x7F800000)>>23;
 double x = GetX(Testfi.i & 0x007FFFFF);

 float f = (float) ( pow(-1,s) * (1+x)* pow(2,(e-127)) );
 printf("计算结果是: %f\n",f);
 printf("目标应该是: %f\n",Testfi.f);
 //输出
 //计算结果是: 16.000000
 //目标应该是: 16.000000

 //测试2
 Testfi.i = 0x43753400;
 //i = 0100 0011 0111 0101 0011 0100 0000 0000
 s = (Testfi.i & 0x80000000)>>31;
 e = (Testfi.i & 0x7F800000)>>23;
 x = GetX(Testfi.i & 0x007FFFFF);

 f = (float) ( pow(-1,s) * (1+x)* pow(2,(e-127)) );
 printf("计算结果是: %f\n",f);
 printf("目标应该是: %f\n",Testfi.f);

 //输出
 //计算结果是: 245.203125
 //目标应该是: 245.203125

 //测试3
 Testfi.i = 0x43434300;
 //i = 0100 0011 0100 0011 0100 0011 0000 0000
 s = (Testfi.i & 0x80000000)>>31;
 e = (Testfi.i & 0x7F800000)>>23;
 x = GetX(Testfi.i & 0x007FFFFF);

 f = (float) ( pow(-1,s) * (1+x)* pow(2,(e-127)) );
 printf("计算结果是: %f\n",f);
 printf("目标应该是: %f\n",Testfi.f);

 //输出
 //计算结果是: 195.261719
 //目标应该是: 195.261719

}

//后记:由于双精度数据的检验,尾数算法稍微复杂,需要两个整数合成,感兴趣的朋友
//可以自己设计。这里不再讨论。另:测试这个程序,vc死了n次,怪 -_-

</PRE>

posted on 2004-12-16 10:50 九月鹰飞 阅读(4515) 评论(2)  编辑 收藏

评论

# 自己做的工具 2005-07-07 10:26 user2nd
我用VC做了一个工具,省去了麻烦的转换,直接读取存储格式。可以到我申请的空间:webuser.home4u.china.com去下来试一下,很方便的。

标题  
姓名  
主页
验证码 *
内容   
  登录  使用高级评论  Top
[使用Ctrl+Enter键可以直接提交]