<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>