数据流浮点数

来源:互联网 发布: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字节

由最高到最低位分别是第313029、……、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 

01

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
指数值7F127 127-127等于0    20次方等于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上的搜索引擎就能解决。

原创粉丝点击