久しぶりに意味が分からないものに出会った。
//無名共用体を試す #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
また考えることにする。