文章来源:http://blog.csdn.NET/educast/article/details/8522818
感谢原作者。
关于16进制浮点数
对于大小为32-bit的浮点数(32-bit为单精度,64-bit浮点数为双精度,80-bit为扩展精度浮点数),
1、其第31 bit为符号位,为0则表示正数,反之为复数,其读数值用s表示;
2、第30~23 bit为幂数,其读数值用e表示;
3、第22~0 bit共23 bit作为系数,视为二进制纯小数,假定该小数的十进制值为x;
则按照规定,该浮点数的值用十进制表示为:
= (-1)^s * (1 + x) * 2^(e - 127)
对于49E48E68来说,
1、其第31 bit为0,即s = 0
2、第30~23 bit依次为100 1001 1,读成十进制就是147,即e = 147。
3、第22~0 bit依次为110 0100 1000 1110 0110 1000,也就是二进制的纯小数0.110 0100 1000 1110 0110 1000,其十进制形式为0.78559589385986328125,即x = 0.78559589385986328125。
这样,该浮点数的十进制表示
= (-1)^s * (1 + x) * 2^(e - 127)
= (-1)^0 * (1+ 0.78559589385986328125) * 2^(147-127)
= 1872333
以上内容为IEEE的标准,现在有个问题,假设我有两台设备在通讯,一个设备向另外一个设备发送数据,这个数据是浮点数,那么我怎么来发送这个数据呢?怎么让接受方知道发送来的是个浮点数呢?而且发送数据要尽量短,最好还要固定长度,也许有人会怎么做:A发送数据3.7586给B,A先将这个浮点数乘以10000变成整型37586,然后将这个整数发送给B,这样使用的弊端是:1、B要事先知道A将这个数字放大了多少倍。2、A需要做一次浮点数的乘法运算,而B要做一次浮点数的除法运算,这对于单片机来说是个负担。3、这样使用会多占用发送数据。因为事先没人知道这个浮点数到底多大。
想了半天,觉得使用IEEE的浮点数规则来发送是最可靠的,因为任何浮点数都被表示成4个字节,这对发送和接收双方都是个好消息,只要双方都知道要进行浮点数的发送就可以了。而且IEEE格式浮点数的转换是机器内部执行的,我们不再需要任何的转换,不增加运算量,不增加代码量。
按照这个原则,编写了测试代码如下:
发送方A:
float fSend; //A需要发送的浮点数据
char chSend[4]; //发送缓冲,经过转换后的浮点数据,变成一个字符型数组。
//以下为转换
chSend[0] = *((char *)(&fSend));
chSend[1] = *((char *)(&fSend) + 1);
chSend[2] = *((char *)(&fSend) + 2);
chSend[3] = *((char *)(&fSend) + 3);
此时A就可以将这个数字发送给B了,B接收到的是4个字节表示的一个浮点数,但需要经过如下转换使用:
float fReceive; //接收到的浮点数
char chReceive[4];//接收缓冲。B将接收到的4个字节保存在这里。
//以下为转换
*((char *)(&fReceive)) = chReceive[0];
*((char *)(&fReceive) + 1) = chReceive[1];
*((char *)(&fReceive) + 2) = chReceive[2];
*((char *)(&fReceive) + 3) = chReceive[3];
好了,此时的B已经得到了一个浮点数fReceive;