关于16进制字符串转为单精度浮点数和双精度浮点数的运算(一)
最近在进行GPIB方面的开发时,传回的数据有这两种格式,1.IEEE 32位浮点数格式;2.IEEE 64位浮点数格式。
1.IEEE 32位浮点数格式
这种格式的特点是:每个数由4字节组成,包括1位符号位,8位带符号阶码,23位尾数。
例如:我们收到一个数的格式是 BE 30 94 00,那么它的二进制格式是:
1 011 1110 0011 0000 1001 0100 0000 0000
这时我们就可以得到这些信息:
符号位:1 (1表明这个数是个负数,0表明这个数是正数)
带符号的阶码:011 1110 0 (转化为整数是124)
尾数:011 0000 1001 0100 0000 0000
首先计算指数:
指数:阶码 - 127 = -3;表明最终对尾数要进行向左位移3位
同理假设算出的指数为5,表明要对尾数进行右移5位。
然后对尾数进行处理:在尾数的最高位加上一个隐藏位1,形成如下二进制格式:
1 011 0000 1001 0100 0000 0000
其中小数点的位置就在刚加的隐藏位后,即:
1.011 0000 1001 0100 0000 0000
根据刚才计算的指数结果-3,小数点左移3位,不够补0,得到最终的浮点数二进制格式为:
0.0010 1100 0010 0101 0000 0000
计算此二进制格式为
0*(2^-1) + 0*(2^-2) + 1*(2^-3) + 0*(2^-4) + 1*(2^-5) + 1*(2^-6) + 0*(2^-7) + 0*(2^-8) + 0*(2^-9) + 0*(2^-10) + 1*(2^-11) + 0*(2^-12) +0*(2^-13) + 1*(2^-14) + 0*(2^-15) + 1*(2^-15)
计算后的十进制数0.17243958,根据前面的符号位可知,这是个负数,所以最终结果是-0.17243958
C语言代码实现如下
long long int getS(int e,int m)
{
long long int s=e;
for (int i=1;i<m;i++)
{
s*=e;
}
return s;
}
float hex2float(unsigned char*p,float& result)
{
long long int a=0x00000000;
a=a|p[0];
a=(a<<8)|p[1];
a=(a<<8)|p[2];
a=(a<<8)|p[3];
//获得符号位,1表示负数,0表示正数
int s=(a>>31)&0xFF;
int e=(a>>23)&0x0FF;
//获得指数
e=e-127;
//获得底数
long long int m=a&0x7FFFFF|0x800000;
long long int c=0;
float v = 0.0f, y = 1.0f;
//向右移动
if (e>0)
{
//获得整数的二进制
c=(m>>(23-e))&0xFFFFFFF;
long int b=0;
for (int i=0;i<23-e;i++)
{
b=(b<<1)|0x01;
}
//获得小数的二进制
b=b&m;
int j=0;
for (int i=23-e-1;i>=0;i--)
{
j++;
y=(double)(((b>>i)&0x01)*getS(2,j));
if (y>0.0)
{
v+=1.0/y;
}
}
v=c+v;
if (s>0)
{
v=-v;
}
}
else
{
//向左移动
e=-e;
c=m;
int j=0;
for (int i=23+e-1;i>=0;i--)
{
j++;
y=(float)(((c>>i)&0x01)*getS(2,j));
if (y>0.0)
{
v+=1.0/y;
}
}
if (s>0)
{
v=-v;
}
}
result = v;
return v;
}