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 のビットレイアウトはどのようにすれば良いか。続きは次回。