10

純粋なLuaで、数値から分数(23ビット)、指数(8ビット)、および符号(1ビット)を生成して、数値がほぼ等しくなるようにしmath.ldexp(fraction, exponent - 127) * (sign == 1 and -1 or 1)、生成されたものをパックする関数を作成したいと思います。値を32ビットに変換します。

数学ライブラリの特定の関数が私の注意を引きました。

frexp関数は、浮動小数点値(v)を仮数(m)と指数(n)に分解し、mの絶対値が0.5以上1.0未満であり、v = m * 2^n。

math.ldexpは逆演算であることに注意してください。

ただし、整数以外の数値を適切にパックする方法は考えられません。この関数によって返される仮数は整数ではないため、使用できるかどうかはわかりません。

math.frexp()仮数として整数を返すのと同様のことを行う効率的な方法はありますか?または、LuaでIEEE754単精度浮動小数点形式で数値をパックするためのより良い方法はありますか?

前もって感謝します。

編集

ここに、私が作成した関数の(うまくいけば)最終バージョンを示します。

function PackIEEE754(number)
    if number == 0 then
        return string.char(0x00, 0x00, 0x00, 0x00)
    elseif number ~= number then
        return string.char(0xFF, 0xFF, 0xFF, 0xFF)
    else
        local sign = 0x00
        if number < 0 then
            sign = 0x80
            number = -number
        end
        local mantissa, exponent = math.frexp(number)
        exponent = exponent + 0x7F
        if exponent <= 0 then
            mantissa = math.ldexp(mantissa, exponent - 1)
            exponent = 0
        elseif exponent > 0 then
            if exponent >= 0xFF then
                return string.char(sign + 0x7F, 0x80, 0x00, 0x00)
            elseif exponent == 1 then
                exponent = 0
            else
                mantissa = mantissa * 2 - 1
                exponent = exponent - 1
            end
        end
        mantissa = math.floor(math.ldexp(mantissa, 23) + 0.5)
        return string.char(
                sign + math.floor(exponent / 2),
                (exponent % 2) * 0x80 + math.floor(mantissa / 0x10000),
                math.floor(mantissa / 0x100) % 0x100,
                mantissa % 0x100)
    end
end
function UnpackIEEE754(packed)
    local b1, b2, b3, b4 = string.byte(packed, 1, 4)
    local exponent = (b1 % 0x80) * 0x02 + math.floor(b2 / 0x80)
    local mantissa = math.ldexp(((b2 % 0x80) * 0x100 + b3) * 0x100 + b4, -23)
    if exponent == 0xFF then
        if mantissa > 0 then
            return 0 / 0
        else
            mantissa = math.huge
            exponent = 0x7F
        end
    elseif exponent > 0 then
        mantissa = mantissa + 1
    else
        exponent = exponent + 1
    end
    if b1 >= 0x80 then
        mantissa = -mantissa
    end
    return math.ldexp(mantissa, exponent - 0x7F)
end

暗黙のビットを利用する方法を改善し、NaNや無限大などの特別な値の適切なサポートを追加しました。私は、リンクされているスクリプトキャットウェルのフォーマットに基づいています。

素晴らしいアドバイスをありがとうございました。

4

2 に答える 2

7

取得した仮数にmath.frexp()2^24を掛け、指数から24を引いて補正します。これで、仮数は整数になります。仮数は23ではなく24ビットであることに注意してください(IEEE-754エンコーディングの暗黙のビットを考慮する必要があります)。

于 2013-01-19T17:14:26.570 に答える
3

これを見たことがありますか?

私はそれがあなたが望むことを少し簡単な方法で行うと思います。

于 2013-01-21T09:48:14.243 に答える