IEEE754浮動小数点数のデコード/エンコード

また、妙な方向に脱線中です。
MSDNを眺めていたら、便利な関数を発見しました。

float ldexp(
    float x,    // 浮動小数点値。
    int exp     // 整数の指数。
);

ldexp 関数は x * 2 の exp 乗の値を返します。

C89から存在する関数のようですが、全然知りませんでした。
これを使えば、

float make_float(
    int exp,    // 指数(バイアス=127)
    long frac)  // 仮数(を2の23乗した値)
{
    return std::ldexp(static_cast<float>(frac), exp-(127+23));
}

として浮動小数点数を簡単に合成できます。


逆に、floatから指数と仮数を取得するのはこの関数です。

float frexp(
    float x,        // 浮動小数点値。
    int * expptr    // 指数部を示す整数の格納場所を指すポインタ。
);

frexp は、仮数部を返します。
frexp 関数は、浮動小数点値 (x) を仮数部 (m) と指数部 (n) に分割します。
m の絶対値が 0.5 以上で 1.0 未満になり、x = m*2n になるようにします。

これを使えば、指数と仮数に分解するのも簡単です。

void split_float(
    float f,
    int& exp,    // 指数(バイアス=127)
    long& frac)  // 仮数(を2の23乗した値)
{
    frac = static_cast<long>(std::ldexp(std::frexp(f, &exp), 23+1));
    exp += (127-1);
}

frexp()の返す仮数が0.5以上1.0未満なので、指数/仮数を一つずらす必要があります。


まだ、0や無限、NaNの処理が抜けていますが、まぁ大体こんな感じです。
std::numeric_limits::is_iec559で場合分けすれば、ネイティブfloatのフォーマットを問わずそれなりに動かせそうです。