Floating point 解析纯Lua中的IEEE754双精度浮点?

Floating point 解析纯Lua中的IEEE754双精度浮点?,floating-point,lua,bit-manipulation,ieee-754,Floating Point,Lua,Bit Manipulation,Ieee 754,我有固定大小的双精度数组,编码为IEEE754格式,有人能告诉我任何可以做相关事情的Lua代码吗 更新:我不能发布这个问题,因为它太短了,所以下面是我在解决这个问题的过程中编写的一些代码-这将二进制字符串转换为类似于“0011000” 看一看。它小而灵活,没有依赖性。我真的需要这样做,并来这里寻求答案。看起来以前没人做过,所以我自己做了一些东西。我并没有详尽地测试每一个案例,但它能够可靠地正确编码和解码数字,输入和输出数字之间没有错误 我编写的函数使用二进制字符串,但是任何需要它的人都应该能够轻

我有固定大小的双精度数组,编码为IEEE754格式,有人能告诉我任何可以做相关事情的Lua代码吗

更新:我不能发布这个问题,因为它太短了,所以下面是我在解决这个问题的过程中编写的一些代码-这将二进制字符串转换为类似于
“0011000”


看一看。它小而灵活,没有依赖性。

我真的需要这样做,并来这里寻求答案。看起来以前没人做过,所以我自己做了一些东西。我并没有详尽地测试每一个案例,但它能够可靠地正确编码和解码数字,输入和输出数字之间没有错误

我编写的函数使用二进制字符串,但是任何需要它的人都应该能够轻松地将其调整为自己的用途

这是我的密码:

--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
——在这里定义一些常用常量,这样我们就不必在运行时这样做
--ln(2),用于沿线路改变基线
本地log2=math.log(2)
--用于将分数转换为(非常大的)整数
局部功率2to52=数学功率(2,52)
--用于位移位
本地f08=数学功率(2,8)
局部f16=数学功率(2,16)
局部f24=数学功率(2,24)
局部f32=数学功率(2,32)
局部f40=数学功率(2,40)
局部f48=数学功率(2,48)
函数编码双精度(数字)
--IEEE双精度浮点数
--规格:https://en.wikipedia.org/wiki/Double-precision_floating-point_format
--把符号、指数和分数分开
局部符号=数字<0和1或0
局部指数=math.ceil(math.log(math.abs(number))/log2)-1
局部分数=math.abs(数字)/math.pow(2,指数)-1
--确保指数保持在范围内-允许的值为-1023到1024
如果(指数<-1023),则
--我们允许这种情况下的次正常数,只是钳制指数,重新计算分数
--没有偏移量1
指数=-1023
分数=数学绝对值(数字)/数学功率(2,指数)
elseif(指数>1024)然后
--如果指数超过这个值,就会出现可怕的错误,我们可能应该停止
错误(“指数超出范围:“…指数”)
结束
--处理特殊情况
如果(数字==0),则
--零
指数=-1023
分数=0
elseif(math.abs(number)=math.gigh)然后
--无穷大
指数=1024
分数=0
elseif(number~=number)则
--楠
指数=1024
分数=(pow2to52-1)/pow2to52
结束
--准备要编码的值
局部指数=指数+1023——指数是一个11位偏移量二进制文件
local fractionOut=fraction*pow2to52——分数是52位的,因此将其乘以2^52将得到一个整数
--将值合并为8个字节并返回结果
返回字符(
128*符号+数学下限(expOut/16),--字节0:符号,然后将指数下移4位
(expOut%16)*16+数学下限(fractionOut/f48),--字节1:将分数上移4以给出最高有效位,将分数下移48
数学地板(fractionOut/f40)%256,--字节2:下移分数40位
数学地板(fractionOut/f32)%256,--字节3:下移分数32位
数学地板(fractionOut/f24)%256,--字节4:向下移动分数24位
数学地板(fractionOut/f16)%256,--字节5:向下移位分数16位
数学地板(fractionOut/f08)%256,--字节6:下移分数8位
floor(fractionOut%256)--字节7:分数的最后8位
)
结束
函数decodeddouble(str)
--从字符串中获取字节
本地字节0=字节(substr(str,1,1))
本地字节1=字节(substr(str,2,2))
本地字节2=字节(substr(str,3,3))
本地字节3=字节(substr(str,4,4))
本地字节4=字节(substr(str,5,5))
本地字节5=字节(substr(str,6,6))
本地字节6=字节(substr(str,7,7))
本地字节7=字节(substr(str,8,8))
--把这些值分开
本地符号=字节0>=128和1或0
局部指数=(字节0%128)*16+数学下限(字节1/16)
局部分数=(字节1%16)*f48
+字节2*f40+字节3*f32+字节4*f24
+字节5*f16+字节6*f08+字节7
--处理特殊情况
如果(指数=2047),则
--无限
如果(分数==0),则返回math.pow(-1,符号)*math.end
--楠
如果(分数==pow2to52-1),则返回0/0结束
结束
--组合这些值并返回结果
如果(指数=0),则
--处理次正常数
返回数学功率(-1,符号)*数学功率(2,指数-1023)*(分数/pow2to52)
其他的
--处理正常数
返回math.pow(-1,符号)*math.pow(2,指数-1023)*(分数/pow2to52+1)
结束
结束

8年后,幸运的是,情况发生了变化:

此处存在一个与其他结构库非常相似的仍在更新的纯lua库:

在其他格式中,它可以解析任意尾数的浮点和双精度

例如:

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

你想做什么需要这个?Lua不是低级语言;这不是你在Lua应该做的事情。如果你想解析一些二进制文件,最好是用一些辅助C或C++代码来读取文件中的整数/浮点等。这是一个只支持LUA扩展的基础结构的组件。你能更好地描述数组中的项目吗?“以IEEE754格式编码的双精度数组”不够清晰。那么,您有字符串数组吗?请包括
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