文章來源: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;