Skip to content

Instantly share code, notes, and snippets.

@LunNova
Last active February 19, 2023 01:43
Show Gist options
  • Save LunNova/9cf050df81619e6a559cfb573b772915 to your computer and use it in GitHub Desktop.
Save LunNova/9cf050df81619e6a559cfb573b772915 to your computer and use it in GitHub Desktop.
function fp_to_bytes(fp, bytes, is_double)
local val = tonumber(fp)
-- it's a NaN or inf
if val ~= val or val == math.huge or val == -math.huge then
bytes[1] = (val ~= val or val == math.huge) and 0x7f or 0xff
bytes[2] = (val ~= val and 0xf9 or 0xf8)
local max = is_double and 8 or 4
for i = 3, max do
bytes[i] = 0
end
return
end
local sign = 0
if val < 0 then
sign = 1
val = -val
end
local mantissa, exponent = math.frexp(val)
if val == 0 then
mantissa = 0
exponent = 0
else
mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, is_double and 53 or 24)
exponent = exponent + (is_double and 1022 or 126)
end
local pos
if is_double then
val = mantissa
for i = 8, 3, -1 do
bytes[i] = math.floor(val) % (2 ^ 8)
val = math.floor(val / (2 ^ 8))
end
else
bytes[4] = math.floor(mantissa) % (2 ^ 8)
val = math.floor(mantissa / (2 ^ 8))
bytes[3] = math.floor(val) % (2 ^ 8)
val = math.floor(val / (2 ^ 8))
end
bytes[2] = math.floor(exponent * (is_double and 16 or 128) + val) % (2 ^ 8)
val = math.floor((exponent * (is_double and 16 or 128) + val) / (2 ^ 8))
bytes[1] = math.floor(sign * 128 + val) % (2 ^ 8)
end
function bytes_to_fp(bytes, is_double)
local n = is_double and 8 or 4
-- NaN or inf
if (bytes[1] == 0x7F or bytes[1] == 0xff) and bytes[2] >= 0xf8 then
if bytes[2] == 0xf8 then
local all_zero = true
for i = 3, n do
if bytes[i] ~= 0 then
all_zero = false
break
end
end
if all_zero then
return bytes[1] == 0x7F and 1/0 or -1/0
end
end
return 0/0
end
local sign = 1
if bytes[1] > 127 then
sign = -1
end
local mantissa = bytes[2] % (is_double and 16 or 128)
for i = 3, n do
mantissa = mantissa * (2 ^ 8) + bytes[i]
end
local exponent = (bytes[1] % 128) * (is_double and 16 or 2) + math.floor(bytes[2] / (is_double and 16 or 128))
if exponent == 0 then
return 0.0
else
mantissa = (math.ldexp(mantissa, is_double and -52 or -23) + 1) * sign
return math.ldexp(mantissa, exponent - (is_double and 1023 or 127))
end
end
function test_roundtrip(inp)
bytes = {}
for i = 1, 8 do
bytes[i] = 0
end
fp_to_bytes(inp, bytes, true)
-- for i, v in ipairs(bytes) do
-- print (i, string.format("%x", v))
-- end
-- print(bytes)
print(inp, "==", bytes_to_fp(bytes, true))
end
test_roundtrip(0)
test_roundtrip(1.234)
test_roundtrip(-9876.5432)
test_roundtrip(1/0)
test_roundtrip(-1/0)
test_roundtrip(0/0)
0 == 0
1.234 == 1.234
-9876.5432 == -9876.5432
inf == inf
-inf == -inf
nan == nan
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment