Lua - 打包IEEE754单精度浮点数 [英] Lua - packing IEEE754 single-precision floating-point numbers

查看:495
本文介绍了Lua - 打包IEEE754单精度浮点数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在纯Lua中生成一个函数,它生成一个分数(23位),一个指数(8位)和一个 (1位),所以这个数字大约等于 math.ldexp(fraction,exponent-127)*(sign == 1 and -1 or 1) $ b $>数据库中的某个函数引起了我的注意:
$ b>
$ b


frexp函数将浮点值(v)分解为尾数(m)和指数(n),使得m的绝对值大于或等于到0.5和小于1.0,v = m * 2 ^ n。

注意math.ldexp是相反的操作。

然而,我想不出有什么办法可以正确打包非整数。由于这个函数返回的尾数不是一个整数,所以我不确定我是否可以使用它。



是否有任何有效的方法来做类似于 math.frexp()它返回一个整数作为尾数?或者是有没有更好的方法在Lua中以IEEE754单精度浮点格式打包数字?



预先感谢您。

编辑



我在这里提出我希望得到的函数的最终版本:



pre $函数PackIEEE754(数字)
如果数字== 0然后
返回string.char(0x00,0x00,0x00, 0x00)
elseif number〜= number然后
返回string.char(0xFF,0xFF,0xFF,0xFF)
else
local sign = 0x00
if number< 0 then
sign = 0x80
number = -number
end
本地尾数,指数= math.frexp(数字)
指数=指数+ 0x7F
如果指数<= 0,那么
mantissa = math.ldexp(尾数,指数-1)
指数= 0
elseif指数> 0 then
if exponent> = 0xFF then
return string.char(sign + 0x7F,0x80,0x00,0x00)
elseif exponent == 1 then
exponent = 0
else
尾数=尾数* 2 - 1
指数=指数 - 1
结束
结束
尾数= math.floor(math.ldexp(尾数, 23)+ 0.5)
return string.char(
sign + math.floor(exponent / 2),
(exponent%2)* 0x80 + math.floor(mantissa / 0x10000),
math.floor(尾数/ 0x100)%0x100,
尾数%0x100)
结束
结束
函数UnpackIEEE754(打包)
本地b1,b2 (b1,0x80)* 0x02 + math.floor(b2 / 0x80)
本地尾数= math.ldexp((b1,b4) (b2%0x80)* 0x100 + b3)* 0x100 + b4,-23)
if exponent == 0xFF then
if尾数> 0 then
return 0/0
else
mantissa = math.huge
exponent = 0x7F
end
elseif exponent> 0然后
尾数=尾数+ 1
else
指数=指数+ 1
结束
如果b1> = 0x80那么
尾数= -mantissa
end
return math.ldexp(尾数,指数 - 0x7F)
结束



我改进了隐式位的使用方式,并增加了对NaN和无穷大等特殊值的适当支持。

我感谢你们两位的宝贵意见。

解决方案

将您从 math.frexp()得到的有效数乘以2 ^ 24,然后从指数中减去24来补偿。现在有效数是一个整数。请注意,有效位是 24 位,而不是23位(您需要考虑IEEE-754编码中的隐式位)。


I want to make a function in pure Lua that generates a fraction (23 bits), an exponent (8 bits), and a sign (1 bit) from a number, so that the number is approximately equal to math.ldexp(fraction, exponent - 127) * (sign == 1 and -1 or 1), and then packs the generated values into 32 bits.

A certain function in the math library caught my attention:

The frexp function breaks down the floating-point value (v) into a mantissa (m) and an exponent (n), such that the absolute value of m is greater than or equal to 0.5 and less than 1.0, and v = m * 2^n.

Note that math.ldexp is the inverse operation.

However, I can't think of any way to pack non-integer numbers properly. As the the mantissa returned by this function is not an integer, I'm not sure if I can use it.

Is there any efficient way to do something similar to math.frexp() which returns an integer as the mantissa? Or is there perhaps a better way to pack numbers in the IEEE754 single-precision floating-point format in Lua?

Thank you in advance.

Edit

I hereby present the (hopefully) final version of the functions I made:

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

I improved the way to utilise the implicit bit and added proper support for special values such as NaN and infinity. I based the formatting on that of the script catwell linked to.

I thank both of you for your great advice.

解决方案

Multiply the significand you get from math.frexp() by 2^24, and subtract 24 from the exponent to compensate. Now the significand is an integer. Note that the significand is 24 bits, not 23 (you need to account for the implicit bit in the IEEE-754 encoding).

这篇关于Lua - 打包IEEE754单精度浮点数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆