無名共用体を使う

久しぶりに意味が分からないものに出会った。

//無名共用体を試す
#include <iostream>
using namespace std;

int main()
{
    union {
        unsigned char bytes[8];
        double value;
    };
    int i;
    value = 859345.324;
    //cout << &bytes << "\n"; //デバッグ用。意味はない。
    //cout << &value << "\n";
    
    //double値内のバイトを表示する
    for(i=0;i<8;i++)
        cout << (int) bytes[i] << " ";
        cout << "\n";
    return 0;

}

出力結果

248 83 227 165 162 57 42 65 

自分の解釈は、
char型(1バイト)の8要素を持つ配列bytes[8](よって8バイトを占有)と
double型の変数value(8バイト)を宣言する。
共用体で宣言されているので、その2つは同じメモリ領域(アドレス)を共有する。
value=の代入のときに、valueに値が入る。
このとき、bytesには何が入っている?と思うのだが、
248 83 227 165 162 57 42 65
が入っているという。
bytesの8つの各要素はchar型で、それをint型にキャストしている。
調べていると、char型からint型へは自動的にキャストされる(暗黙の型変換)とのこと。
はて、char型ってアルファベットとかの1文字のことじゃなかったっけと思ったので調べると、
数字もchar型であることに気づく。
実際、char型はアルファベットなどの文字を表す→bytesに入ってる248とかの数字は
ASCIIコードで、int型にキャストしたから整数になってるんだと思った。
つまり、配列bytesに対して何らかの初期化が行われた(この場合は共用体のメンバvalueに対する代入に連動して何かが起こった)と仮定した。
ここで、ASCIIコードを見ると、128までしかない。。。(ASCIIは7ビット、それを8ビットに拡張したのがJIS X 0211なのね)。のっけからこの仮説は崩れる。
ここで、double型の規格を疑う。
http://www.cc.kyoto-su.ac.jp/~yamada/programming/float.html
たぶんこれだ。

248 83 227 165 162 57 42 65 

を2進数に変換すると(8ビットにするため、各バイトの先頭に0を挿入した)、

11111000 01010011 11100011 10100101 10100010 00111001 00101010 01000001

さて、double型の規格は
符号部1ビット、指数部11ビット、仮数部52ビットの計64ビット=8バイトである。
まず、符号部は1。
指数部は、1111000 010 = 962
仮数部は、10011 11100011 10100101 10100010 00111001 00101010 01000001 = 5598325088266817
どういうことだ。。。
と思ったら、次の公式があるとのこと。

double の表す値 = (-1)^符号部 × 2^(指数部-1023) × 1.仮数

なるほど。こんなアルゴリズムだったのか。
そうすると、
符号は-1。
指数部は、962 - 1023 = -61
仮数部は、1.5598325088266817
これを計算すると、

import math
ans = -1.0*1.5598325088266817*(2**(-61))
print ans
-6.76469517913e-19

また考えることにする。