Flonum
Fixnum を紹介したので、次は Flonum を紹介する。
Flonum は聞き慣れない言葉ではないかと思うのだが、Float オブジェクト(浮動小数点数オブジェクト)を Immediate として表現するためのものだ。 Fixnum は Integer の一部(63bit で表現できる整数値)だったが、Flonum も同様に、浮動小数点数の一部を軽量に表現するものになる。
64bit CPU 限定で動作する(32bit CPU では有効にならない)。
Ruby の浮動小数点数は IEEE 754 - Wikipedia 倍精度浮動小数点数で表現されるので、64 bit 幅が必要になる。VALUE 幅は 64bit CPU だと 64 bit なので、だいぶ近い。少し頑張れば入りそうではないか? と思って頑張って入れたのが Flonum。
さて、どうやって入れるか。まず、Immediate でなければならず、さらに Flonum であることを示さなければならないため、下位 2 bit は 0b10 となっている。つまり、(v & 0x03) == 0x02
であれば、Flonum ということになる。
次は、64bit 倍精度小数点数(面倒だから、double と書こう)をどうやって 62 bit に押し込むか。
IEEE 754 double の表現は、次のようになっている。
- s: 符号 1 bit
- e: 指数 11 bit
- m: 仮数 52 bit
の合計 64 bit で構成されている(s から上位ビット)。数値は、-1s * 2e-1024 * m (m = 1 + Σ i=0; 51; bi/(252-i)) で得られる。数式は適当に書いているし、なんか難しそうだけれど、e がどれくらい大きいか、m がどれくらい精度を持つか、で覚えておけばいい。
さて、どこから2ビットを削るか、というのが問題。仮数部が一番ビット数多いんだけど、仮数部を2ビット減らすと、つまり精度が落ちることになる。「Ruby で計算すると、なんか変な値になる」(変、とは...)、ってなるのは嫌だ。
それなら、e を削る方がいいかな、ということで、e から 2 bit 拝借することにした。double は指数部として 2^-1024 ~ 21023 の範囲を表すことができるが、2^-256~2255 の範囲だけ Flonum で表現できればいいか、と考える。実際、その範囲はどれくらいよ、ということなんだけど、2256 = 1.1579208923731619542357098500869e+77 らしく、まぁ、普通の人はこんなに大きな数も使わないよな、ということで、多分大丈夫なんだと思う。
e は 11 bit なので 0~2047 の範囲が表現できるが、バイアス 1024 を引くので、指数として表現出来るのは -1024 ~ 1023 になる。今回は、指数が -256 ~ 255 なので、
if (e >= -256 && e<= 255) { // flonum } else { // flonum じゃない格納方法 }
みたいに分けることになる。さて、2ビットを削った Flonum のビットレイアウトはどのようにすれば良いか。続きは次回。