Lua - IEEE754 single precision floating point packaging

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

Some function in the math library caught my attention:

The frexp function destroys the floating point value (v) in the mantissa (m) and exponent (n), so 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 figure out how to properly pack non-integer numbers. Since the mantissa returned by this function is not an integer, I'm not sure if I can use it.

Is there an efficient way to do something similar to math.frexp() that returns an integer as a mantissa? Or maybe the best way to pack IEEE754 single precision floating-point numbers in Lua?

Thanks in advance.

Edit

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

 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 I use the implicit bit and added proper support for special values ​​like NaN and infinity. I based formatting on a catwell script related to.

I thank both of you for your excellent advice.

+8
floating-point ieee-754 lua pack
source share
2 answers

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

+7
source share

Have you seen this ?

I think it makes what you want a little easier.

+4
source share

All Articles