原创 浮点数 换成 字节 保存到EEPROM

2010-3-12 18:11 6456 5 5 分类: MCU/ 嵌入式

保存浮点数到EEPROM,由于I2C 每次只能保存1个字节即8位,但一个folat等于4个字节32位.


 


目前大多数高级语言(包括C)都按照IEEE-754标准来规定浮点数的存储格式,IEEE754规定,单精度浮点数用4字节存储,双精度浮点数用8字节存储,分为三个部分:符号位、阶和尾数。阶即指数,尾数即有效小数位数。单精度格式阶占8位,尾数占24位,符号位1位,双精度则为11位阶,53位尾数和1位符号位,如下图所示:


根据IEEE的标准,浮点数的定义如下


             符号位      指数位          小数部分      指数偏移量


单精度浮点数 1 位[31]    8位 [30-23]     23位 [22-00]       127


双精度浮点数 1 位[63]    11 位[62-52]     52 位[51-00]       1023


 


细心的人会发现,单双精度各部分所占字节数量比实际存储格式都多了一位,的确是这样,事实上,尾数部分包括了一位隐藏位,允许只存储23位就可以表示24位尾数,默认的1位是规格化浮点数的第一位,当规格化一个浮点数时,总是调整它使其值大于等于1而小于2,亦即个位总是为1。例如1100B,对其规格化的结果为1.1乘以2的三次方,但个位1并不存储在23位尾数部分内,这个1是默认位。


说明:符号位,表述浮点数的正或者负;指数实际也有正负的,但是没有单独的符号位,而是采用了一个偏移来表示。


在计算机的世界里,进位都是二进制的,指数表示的也是2的N次幂


这个数据格式当中的,指数是8位,可表达的范围是0到255


而对应的实际的指数是-127到+128。这里特殊说明,-127和+128这两个数据在IEEE当中是保留的用作多种用途的:-127表示的数字是0,而128和其他位数组合表示多种意义,最典型的就是NAN状态


阶以移码的形式存储。对于单精度浮点数,偏移量为127(7FH),而双精度的偏移量为1023(3FFH)。存储浮点数的阶码之前,偏移量要先加到阶码上。前面例子中,阶为2的三次方,在单精度浮点数中,移码后的结果为127+3即130(82H),双精度为1026(402H)。


浮点数有两个例外。数0.0存储为全零。无限大数的阶码存储为全1,尾数部分全零。符号位指示正无穷或者负无穷。


可以用一个类来表示:


class FloatType


{


public:


     union {


         DWORD m_dwInt;


         float m_fFloat;


         struct  {


          bool   m_bSign : 1;


          int    m_nExp  : 8;


          int    m_nFra  : 23;


      }


}


下面举几个例子:


单精度浮点数 十进制 规格化 符号 移阶码 尾数


-12 -1.1x2^3 1 10000010 1000000 00000000 00000000


0.25 1.0x2^-2 0 01111101 0000000 00000000 00000000


所有字节在内存中的排列顺序,intel的cpu按little endian顺序,motorola的cpu按big endian顺序排列。


=====================================


比如+178.125把它按照单精度浮点数的格式进行规格化。


首先+178的二进制表示为1011 0010 ;而0.125为0.001


那么它就是10110010.001,可以看到它的指数应该是7=0b0111它的移码为10000110,相加之后 应该是 0100 0011 0011 0010 0010 0000 0000 0000


浮点数的存储:将运算的结果(浮点数)存入eeprom中。我们知道,浮点数在c语言中是以IEEE-754格式存储的,一个浮点数占用四个字节,例如浮点数34.526存为(160,26,10,66)这四个数(十进制)。要将一个浮点数存入eeprom,实际上就是要存这四个数。那么如何在程序中得到一个浮点数的组成数呢?


浮点数在存储时,是存储连续的字节中的,只要设法找到存储位置,就可以得到这些数了。可以定义一个void的指针,将此指针指向需要存储的浮点数,然后将此指针强制转化为char型,这样,利用指针就可以得到组成该浮点数的各个字节的值了。具体程序如下:


 


#define uchar  unsigned char


#define uint   unsigned int


void ftoc(void)


{ float a;


uchar i,*px;


uchar x[4]; /*定义字符数组,准备存储浮点数的四个字节*/


void *pf;


px=x; /*px指针指向数组x*/


pf=&a; /*void 型指针指向浮点数首地址*/


a=34.25;


for(i=0;i<4;i++)


  *(px+i)=*((char *)pf+i); /*强制void 型指针转成char型,因为void型指针不能运算*/


for(i=0;i<4;i++)


 printf("%x\n",x);


}


如果已将数存入eeprom,要将其取出合并,方法也是一样,可参考下面的程序。


void ctof(void)


{ float a;


uchar i,*px;


uchar x[4]={0xa0,0x1a,0xa,0x42};


void *pf;


px=x;             //px指针指向数组x


pf=&a;


for(i=0;i<4;i++)


 *((char *)pf+i)=*(px+i);


 printf("%f\n",a);


}


 


注:s 指数 尾数(从高字节到低字节)如:+178.125为:


0x43322000即:0100 0011 0011 0010 0010 0000 0000 0000


 


以上是从网上转来的方法,比较麻烦,我这里用的方法(也是一个老工程师教的):


用一个union 把float与一个char[4]数组共用内存的方式存储.

文章评论0条评论)

登录后参与讨论
我要评论
0
5
关闭 站长推荐上一条 /2 下一条