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.