我有以IEEE754格式编码的固定大小的双精度数组,有人能指出任何可以做相关事情的Lua代码吗?
更新:我不能发布这个问题,因为它太短了,所以这里有一些我在编写过程中编写的代码 - 这会将二进制字符串转换为像{{1}这样的字符串}
"0011000"
答案 0 :(得分:1)
幸运的是,八年后,景观发生了变化:
此处仍存在与其他结构库非常相似的仍在更新的纯lua库:https://luarocks.org/modules/deepakjois/vstruct
在其他格式中,它可以解析任意大小的浮点数和双精度数。
示例:
local readfloat = vstruct.compile("f4") -- compile a parser, f4 is a 4 byte float
local results = {}
readfloat:read("aaaa",results) -- can return either a new table or reuse one as done here
print(results[1]) -- 2.5984589414244e+20
答案 1 :(得分:0)
我实际上需要执行此操作,然后来到这里寻求答案。看起来以前没有人做过,所以我最终做了自己的事情。我没有对每种情况进行详尽的测试,但是它能够可靠地正确编码和解码数字,而输入和输出数字之间没有错误。
我编写的函数适用于二进制字符串,但是任何需要此功能的人都应该能够轻松地将其改编为自己的用途。
这是我的代码:
--Define some commonly used constants here so we don't have to do this at runtime
--ln(2), used for change of base down the line
local log2 = math.log(2)
--Used to convert the fraction into a (very large) integer
local pow2to52 = math.pow(2,52)
--Used for bit-shifting
local f08 = math.pow(2, 8)
local f16 = math.pow(2,16)
local f24 = math.pow(2,24)
local f32 = math.pow(2,32)
local f40 = math.pow(2,40)
local f48 = math.pow(2,48)
function encodeDouble(number)
--IEEE double-precision floating point number
--Specification: https://en.wikipedia.org/wiki/Double-precision_floating-point_format
--Separate out the sign, exponent and fraction
local sign = number < 0 and 1 or 0
local exponent = math.ceil(math.log(math.abs(number))/log2) - 1
local fraction = math.abs(number)/math.pow(2,exponent) - 1
--Make sure the exponent stays in range - allowed values are -1023 through 1024
if (exponent < -1023) then
--We allow this case for subnormal numbers and just clamp the exponent and re-calculate the fraction
--without the offset of 1
exponent = -1023
fraction = math.abs(number)/math.pow(2,exponent)
elseif (exponent > 1024) then
--If the exponent ever goes above this value, something went horribly wrong and we should probably stop
error("Exponent out of range: " .. exponent)
end
--Handle special cases
if (number == 0) then
--Zero
exponent = -1023
fraction = 0
elseif (math.abs(number) == math.huge) then
--Infinity
exponent = 1024
fraction = 0
elseif (number ~= number) then
--NaN
exponent = 1024
fraction = (pow2to52-1)/pow2to52
end
--Prepare the values for encoding
local expOut = exponent + 1023 --The exponent is an 11 bit offset-binary
local fractionOut = fraction * pow2to52 --The fraction is 52 bit, so multiplying it by 2^52 will give us an integer
--Combine the values into 8 bytes and return the result
return char(
128*sign + math.floor(expOut/16), --Byte 0: Sign and then shift exponent down by 4 bit
(expOut%16)*16 + math.floor(fractionOut/f48), --Byte 1: Shift fraction up by 4 to give most significant bits, and fraction down by 48
math.floor(fractionOut/f40)%256, --Byte 2: Shift fraction down 40 bit
math.floor(fractionOut/f32)%256, --Byte 3: Shift fraction down 32 bit
math.floor(fractionOut/f24)%256, --Byte 4: Shift fraction down 24 bit
math.floor(fractionOut/f16)%256, --Byte 5: Shift fraction down 16 bit
math.floor(fractionOut/f08)%256, --Byte 6: Shift fraction down 8 bit
math.floor(fractionOut % 256) --Byte 7: Last 8 bits of the fraction
)
end
function decodeDouble(str)
--Get bytes from the string
local byte0 = byte(substr(str,1,1))
local byte1 = byte(substr(str,2,2))
local byte2 = byte(substr(str,3,3))
local byte3 = byte(substr(str,4,4))
local byte4 = byte(substr(str,5,5))
local byte5 = byte(substr(str,6,6))
local byte6 = byte(substr(str,7,7))
local byte7 = byte(substr(str,8,8))
--Separate out the values
local sign = byte0 >= 128 and 1 or 0
local exponent = (byte0%128)*16 + math.floor(byte1/16)
local fraction = (byte1%16)*f48
+ byte2*f40 + byte3*f32 + byte4*f24
+ byte5*f16 + byte6*f08 + byte7
--Handle special cases
if (exponent == 2047) then
--Infinities
if (fraction == 0) then return math.pow(-1,sign) * math.huge end
--NaN
if (fraction == pow2to52-1) then return 0/0 end
end
--Combine the values and return the result
if (exponent == 0) then
--Handle subnormal numbers
return math.pow(-1,sign) * math.pow(2,exponent-1023) * (fraction/pow2to52)
else
--Handle normal numbers
return math.pow(-1,sign) * math.pow(2,exponent-1023) * (fraction/pow2to52 + 1)
end
end
答案 2 :(得分:-1)
看看Lua-struct。它小而灵活,没有依赖性。