Lua - упаковка чисел с плавающей точкой одинарной точности IEEE754
Я хочу сделать функцию в чистом 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 ^ п.
Обратите внимание, что math.ldexp является обратной операцией.
Тем не менее, я могуНе придумайте, как правильно упаковать нецелые числа. Поскольку мантисса, возвращаемая этой функцией, не является целым числом, яЯ не уверен, что смогу это использовать.
Есть ли эффективный способ сделать что-то похожее наmath.frexp()
который возвращает целое число как мантисса? Или, возможно, есть лучший способ упаковать числа в формате с плавающей запятой IEEE754 с одинарной точностью в Lua?
Заранее спасибо.
редактировать
Настоящим я представляю (надеюсь) окончательную версию функций, которые я сделал:
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
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 и бесконечность. Я основал форматирование на том сценарии, который связан с.
Я благодарю вас обоих за отличный совет.