91185


こんにちは，  
今回はArduinoのfloat, つまりIEEE 754表現について教えていただきたいです．

floatは4byteで構成されていますが，その1byteずつを数字で表すとどうなるのでしょうか？２進数でも，10進数でも，16進数でも構いません.

たとえば，pi=3.141592というfloatは，1byteずつ数字で表すとどうなりますでしょうか？

いただいた回答は，私の手持ちのプログラムによって，

[code]

    data[0]=上位1byte 
    data[1]=次の1byte 
    data[2]=次の次の1byte 
    data[3]=下位1byte 
    
[/code]

として格納し，以下のようなbitシフトを使って元の値に戻るか確かめます．(もしbitシフトの方法も間違えているようであれば教えてくださいませ）

[code]

    float re_pi = (float) (
          (((uint32_t)data[0] << 24) & 0xFF000000)
        | (((uint32_t)data[1] << 16) & 0x00FF0000)
        | (((uint32_t)data[2] <<  8) & 0x0000FF00)
        | (((uint32_t)data[3] <<  0) & 0x000000FF)
    );
    
[/code]

9/20追記 SPIに使っているコードを追記します．

[code]

    #include <SPI.h>
    
    volatile uint32_t data[4];
    volatile uint8_t count=0;
    
    
    
      
    void setup(){
        Serial.begin(115200);
        SPCR |= _BV(SPE);
        SPI.attachInterrupt();  // (3)
    }
    
    void loop(){
        
       
    }
    
    
    
    ISR(SPI_STC_vect){  // (4)
      
      data[count]=SPDR;
      count += 1;
      
      if(count==4){
        count=0;
       
       
        float result = (float) (
              (((uint32_t)data[0] << 24) & 0xFF000000)
            | (((uint32_t)data[1] << 16) & 0x00FF0000)
            | (((uint32_t)data[2] <<  8) & 0x0000FF00)
            | (((uint32_t)data[3] <<  0) & 0x000000FF)
        );
        
        Serial.println(result);
      
      }
    }
    
[/code]


CC BY-SA 4.0
2022-09-19T12:04:03.800
91177
2022-09-20T04:45:32.323
2022-09-20T04:45:32.323
41334
41334
question
c++ c arduino
ArduinoのfloatつまりIEEE 754表現の，1byteずつに着目したいです


こういうのは自分の手でいろいろ試してみるのが吉。  
[浮動小数点数内部表現シミュレータ](https://tools.m-bsys.com/calculators/ieee754.php)  
これによると `3.141592` は `0x40490FD8` だそうな。

んで、後者の代入なんですが文法的には正しいのですが `0x40490FD8` という整数（１０進数表記すると `1078530008`） を `float`
に代入するという意味に解釈されるので期待した動作にはならないでしょう。なのでここは別途の工夫が必要です。今のこの時点では宿題にしておこう。

通信で送る受けるの際にはたいていバイト列として送るとよいのですが、先の値を

  * 0x40 0x49 0x0F 0xD8 の順に送るか
  * 0xD8 0x0F 0x49 0x40 の順に送るか

は送る側と受ける側での事前の合意が必要です（ネットワーク電文の設計っスね）  
そして(先の変換の話に絡んでくるので)こういうときは[エンディアネス](https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%87%E3%82%A3%E3%82%A2%E3%83%B3)という話が必ず出てきます。
Arduino がどっち raspberrypi がどっちかは練習なので自分で調べてみましょう。

* * *

SPI 通信って１つのトランザクション内でコマンドとデータが不可分なので、コメントにある通り受信側はたいてい「コマンドとデータが１つにまとまった値」を
(32bit なり 16bit なりで) 受け取ることになります。今欲しいのはそのうちのデータペイロード 8bit
分だけのはず。よって受信側はデータ部だけを抽出するコードが必要です。

[code]

    // コンパイルとか一切してない手書きプログラムっス
    uint32_t data[4]; // SPI 受信結果の生データ（コマンドを含むもの）
    union my_receive_data_converter_type {
        uint8_t bytes[4]; // SPI 受信１回に含まれるペイロードバイト
        float value; // SPI 受信４回で成立する float の値
    };
    my_recive_data_coverter_type f;
    // ペイロードバイトが 32bit 値の下位 8bit に入っているとして
    for (int i=0; i<4; ++i) { f.bytes[i]=(uint8_t)(data[i]&0xFF); }
    DebugPrint(f.value);
    
[/code]

こんな感じ。このコードを実行するタイミングがいつであるとかはあえて省略しますので考えてみてください。

このサンプル自体はエンディアンについては意識していません。どこをどう修正すると「バス上観測されるであろう信号のエンディアン」「メモリに格納する際のエンディアン」が変わるかも宿題にしときます。

# SPI の場合 32bit Transaction で 16bit Payload が運べそうな気がする。


CC BY-SA 4.0
2022-09-19T23:30:13.947
91185
2022-09-20T01:49:25.590
2022-09-20T01:49:25.590
8589
8589
91177
answer


`float re_pi = *((float*)data);` ででてくるんじゃないかと。


CC BY-SA 4.0
2022-09-20T00:06:34.640
91186
2022-09-20T00:06:34.640
27481
91177
answer