IEEE754 単精度浮動小数点数の形式:binary32 の変換
C言語の実数floatは、メモリの中では32ビットの領域を使います。
- 符号ビット: 1ビット
- 指数部の幅: 8ビット
- 仮数部の幅: 23ビット
32ビット=4バイトのデータは、たとえば、16進で表現すると、
41 c8 00 00
は、実数の25.0です。プログラムで外部とのやり取りで実数を扱えないとき、ASCIIコードだけでデータを送ったり受けることができます。
●メモリの内容を読み出す
共用体unionは、同じメモリ領域に複数の変数を定義できます。Arduino IDE 1.8.13 ESP32で実行しました。
a.x = 3.141592;は実数です。そこを整数型で8桁表示させると、メモリの内容が読み出せます。
union { float x; int i; } a; a.x = 3.141592; int i; printf("x= %f \n", a.x); printf("IEEE 754 binary32内部形式は 0x%08x \n", a.i); printf("xのアドレスは 0x%x \n", (unsigned int)&a.x);
実行結果です。
x= 3.141592 IEEE 754 binary32内部形式は 0x40490fd8 xのアドレスは 0x3ffb1f8c |
別の方法です。
実数piのポインタ&piを4バイトのint型でキャストをし、そこが指している内容を読み出します。
float pi = -3.141592; Serial.print("元のデータ ");Serial.println(pi,6); uint32_t ii = *((uint32_t*)&pi); Serial.print("IEEE 754 binary32内部形式は ");Serial.println(ii,HEX);
●戻す
符号、仮数、指数をそれぞれ分離し、最後に全部かけて、小数点6桁を表示します。
(2021/11/25 修正)
int8_t f = pow(-1, int(bitRead(ii,31))); double k = 1 + (double)((((ii<<1)<<8)>>9))/pow(2,23); float s = (float)pow(2,(int8_t)((uint8_t)((ii<<1)>>24)-127)); Serial.print("内部形式を実数に戻した ");Serial.println(f*k*s,6);
実行結果です。
元のデータ -3.141592 IEEE 754 binary32内部形式は C0490FD8 内部形式を実数に戻した -3.141592 |
●確認
Floating Point to Hex Converterのサイトに行って確認します。
●python
pythonではstruct.packを使う4桁のバイト列が得られます。
初めてのRaspberry Pi BLEプログラミング (5) BME280②温度、気圧、湿度
struct.unpackを使うとと簡単に元の実数へ戻せます。
センサ・シリーズ 温湿度①SHT31 その5 BLEセントラル
(参考にしたURL)浮動小数点数の内部表現を取得してみよう