数据流浮点数
来源:互联网 发布:windows server 97 编辑:程序博客网 时间:2024/05/16 10:01
1.在解剖Engine Control Module数据流中,遇到4个字节控制的。由于之前也遇到过,所
以有点信心。变化了一些数据,结果都是0.0,可能结果太小了,因为原厂设备一般保留
2位小数,于是换个区间值测试,结果显示的数据大得惊人,都E14 E15,而且有效数据
N多位,这可吓到没见识过大场面的我了。
2.参考前人协议文件,他的算法是这么写的:
if(x1<0x80)
if(x2<0x80) y=(1+(x2*65536+x3*256+x4)/8388608)*pow(2,((x1*2-128)+1));
else y=((x2*65536+x3*256+x4)/4194304)*pow(2,((x1*2-128)+1));
else
if(x2<0x80) y=-(1+(x2*65536+x3*256+x4)/8388608)*pow(2,((x1*2-384)+1));
else y=-((x2*65536+x3*256+x4)/4194304)*pow(2,((x1*2-384)+1));
没注释,都是数字,看了但没懂。
初步了解有符号、是2的指数幂,还是有点线索,第一时间联想到浮点数,但具体也有点模糊。
3.于是上网搜索,好吧,开始复习下浮点数。
运算表达式 a = m × b^e
m 是尾数 b 是基数(这里是2) e是指数
float
共计32位,折合4字节
由最高到最低位分别是第31、30、29、……、0位
31位是符号位,1表示该数为负,0反之。
30-23位,一共8位是指数位。
22-0位,一共23位是尾数位。
每8位分为一组,分成4组,分别是A组、B组、C组、D组。
每一组是一个字节,在内存中逆序存储,即:DCBA。
X1 X2 X3 X4
| | S |<- 指数 ->|<- 尾数 ->|
1 bit 8 bit 23 bit
(1)符号位S
0正1负
(2)指数 8 bit
8bit无符号数数值范围 0~255
有符号数数值范围 -128~127
指数当然可以有符号,但取值并不是-128~127,而是-127~128,只是偏移了127
不信吧,我看到也不信,好像印象又有这么回事,不过没关系,写个程序验证下。
#include "stdafx.h"
#include <iostream.h>
int main(int argc, char* argv[])
{
float fTmp = 2.0f; /*test value 1.0f 0.5f 2.0f*/
float* pFTmp = &fTmp;
unsigned char* pCTmp = (unsigned char*)pFTmp;
for(int i=3;i>=0;i--)
{
cout << hex << (int)*(pCTmp+i) << endl;
}
return 0;
}
或者换种数据结构,可能程序更清晰
#include "stdafx.h"
#include "iostream.h"
union type
{
float f;
unsigned char ch[4];
}tmp;
int main(int argc, char* argv[])
{
tmp.f = 1.0f; /*test value 0.5f 1.0f 2.0f*/
for(int i=3;i>=0;i--)
cout << hex << (int)tmp.ch[i] << endl;
return 0;
}
编译环境:C++,用VC编译即可
当fTmp = 1.0f时,输出 3F 80 00 00,
指数值7F(127) 127-127等于0 2的0次方等于1.0,确实这么回事。
(3)尾数
a.尾数这里需要注意一点,就是需要规格化。即化成1.xxxx的形式,在存储时1将省略。
如上的输出3F 80 00 00, 尾数为全0,由于省略1,所以1.0*2^0 == 1.0
b.尾数的计算
1 + n0*2^-1 + n1*2^-2 + …… + nm*2^-(m+1)
1 + n0*0.5 + n1*0.25 + ……
然而这种算法,不容易用简单的语句表达,因为我们的产品的算法库编译器只支持
单一的逻辑判断语句(当然可以拆开一句一句的调用编译)。
这里我们使用均分的思想计算,即23bit尾数将1进行2^23等分:那么:
1 + value * (1 / 2^23)
value = X2 的低7bit X3 X4 的无符号整数值
4.基于上面的知识,现在我们有能力给出算法了,根据公式a = m × b^e :
y = pow(-1 , X1.bit7) * // + - 符号
(1 + ((X2&0x7F)*65536 + X3*256 + X4) * //尾数
pow(2 , (X1&0x7F)*2 – X2.bit7 -127 ) ) //指数
由于编译器没有指数操作符,也不支持pow()函数,所以还是需要
特殊处理。最好让编译器支持float(x1,x2,x3,x4),我做过尝试,将
编译函数移植到VC下,然后添加float()处理,效果不错,很方便。
5.当然第4部分中仅仅得到了4个字节存储结果对应的浮点数的值,有时还要乘以乘数。
就像unsigned char 只能表示0~255,当乘数为2,则能表示0 2 4 ~ 510
关于精确解剖乘数,小弟还没找到很好的方法,就留给日后探讨。
6.最后希望公司BBS上有个技术经验模块,多年后,能够积累众多技术骨干的经验,
到时能有个“经验数据库”,当新员工遇到问题时,通过BBS上的搜索引擎就能解决。