Lua 将浮点值转换为十六进制

Lua 将浮点值转换为十六进制,lua,floating-point,nibble,Lua,Floating Point,Nibble,我正在为Lua中的浮点到十六进制转换而挣扎。我的应用程序与旧的Akai S2000采样器通信。采样器将两个字节的消息编码为四个半字节值。半字节的顺序相反,因此最重要的半字节是最后一个。有一个参数使用值的分数部分的二进制编码。两个MS半字节用于编码值的整数部分,LS半字节用于编码二进制分数 基于这个讨论,我已经开始实现一个Lua算法,从给定的参数值生成这些半字节值。由于我不太擅长计算,我认为我做的很多事情都是错误的。应该有一种更简单的方法来计算这些值,并避免我的许多愚蠢的if/else黑客行为 我

我正在为Lua中的浮点到十六进制转换而挣扎。我的应用程序与旧的Akai S2000采样器通信。采样器将两个字节的消息编码为四个半字节值。半字节的顺序相反,因此最重要的半字节是最后一个。有一个参数使用值的分数部分的二进制编码。两个MS半字节用于编码值的整数部分,LS半字节用于编码二进制分数

基于这个讨论,我已经开始实现一个Lua算法,从给定的参数值生成这些半字节值。由于我不太擅长计算,我认为我做的很多事情都是错误的。应该有一种更简单的方法来计算这些值,并避免我的许多愚蠢的if/else黑客行为

我的代码(粘贴在下面)适用于正数,但使用负数要困难得多

在我的测试中,我添加了具有预期值的表。每个表的工作原理如下:

key = give value * 100 
value = expected outcome from my algorithm
即,PositionEnumbers表中的第一个条目表示0.01的输入值,该值的预期输出是一个包含02 00的四字节内存块(前两个字节表示分数,后两个字节表示整数部分)

目前我的算法在-0.94处失败,我无法绕过它而不中断其他值

有没有人是位计算的字符串,很容易看出我犯的任何错误,特别是在转换负值时? 任何帮助或指点都将不胜感激

Lua代码:

function float2nibbles(value)
    local nibbles = MemoryBlock(4, true)

    -- Retreive integral and fraction parts of the given value to be converted
    local integ, fract = math.modf(math.abs(value))

    -- Calculate the values of the integral part (last two nibbles)
    local bi = BigInteger(integ)
    if value < 0 then
        -- This variable is sometimes added in the negative conversion of the MS nibbles
        local lsAdd = 1
        if integ == 0 then
            lsAdd = 0
        end
        nibbles:setByte(2, bit.band(bit.bnot(bi:getBitRangeAsInt(0,4)) + lsAdd, 0xF))
        nibbles:setByte(3, bit.band(bit.bnot(bi:getBitRangeAsInt(4,4)), 0xF))
    else
        nibbles:setByte(2, bit.band(bi:getBitRangeAsInt(0,4), 0xF))
        nibbles:setByte(3, bit.band(bi:getBitRangeAsInt(4,4), 0xF))
    end

    -- Calculate the values of the fraction (first two nibbles)
    local remainder = fract
    local prevRemain = 0
    for i = 1,2 do
        remainder = remainder * 16
        -- Integral part of the remainder
        local d = math.modf(remainder)
        if value < 0 and fract ~= 0 then
            local lsAdd = 1
            if fract == 0 or i == 1 then
                lsAdd = 0
            end
            console(string.format("lsAdd %d", lsAdd))
            nibbles:setByte(2 - i, bit.band(bit.bnot(d) + lsAdd, 0xF))
        else
            nibbles:setByte(2 - i, bit.band(d, 0xF))
        end
        console(string.format("fract %d = %d, %.2f", i, d, remainder))
        prevRemain = remainder
        remainder = remainder - d
    end

    -- For some reason this increment helps when the LS nibble should increment the value of the second nibble
    if nibbles:getByte(0) == 0 and nibbles:getByte(1) ~= 0 and value < 0 then
        console(string.format("weird increment { %d %d }", nibbles:getByte(0), nibbles:getByte(1)))
        nibbles:setByte(1, nibbles:getByte(1) + 1)
    end

    -- The precision of this data is one byte but apparently they seem to use a third increment to check for rounding
    remainder = remainder * 16
    console(string.format("final remainder %.2f", remainder))
    if math.abs(remainder - prevRemain) > 0.001 and remainder > 14 then
        console(string.format("overflow -> %.2f (%.2f)", remainder, prevRemain))
        if value < 0 then
            nibbles:setByte(0, nibbles:getByte(0) - 1)
        else
            nibbles:setByte(0, nibbles:getByte(0) + 1)
        end
    end

    console(string.format("%.2f : integral part %s (%s), fract %.2f", value, bit.tohex(integ, 2), nibbles:toHexString(1), fract))
    return nibbles
end

local positiveNumbers = {   
    "02 00 00 00",
    "05 00 00 00",
    "07 00 00 00",
    "0A 00 00 00",
    "0C 00 00 00",
    "0F 00 00 00",
    "02 01 00 00",
    "04 01 00 00",
    "07 01 00 00",
    "09 01 00 00",
    "0C 01 00 00",
    "0E 01 00 00",
    "01 02 00 00",
    "03 02 00 00",
    "06 02 00 00",
    "09 02 00 00",
    "0B 02 00 00",
    "0E 02 00 00",
    "00 03 00 00",
    "03 03 00 00",
    "05 03 00 00",
    "08 03 00 00",
    "0B 03 00 00",
    "0D 03 00 00",
    "00 04 00 00",
    "02 04 00 00",
    "05 04 00 00",
    "07 04 00 00",
    "0A 04 00 00",
    "0C 04 00 00",
    "0F 04 00 00",
    "02 05 00 00",
    "04 05 00 00",
    "07 05 00 00",
    "09 05 00 00",
    "0C 05 00 00",
    "0E 05 00 00",
    "01 06 00 00",
    "03 06 00 00",
    "06 06 00 00",
    "09 06 00 00",
    "0B 06 00 00",
    "0E 06 00 00",
    "00 07 00 00",
    "03 07 00 00",
    "05 07 00 00",
    "08 07 00 00",
    "0B 07 00 00",
    "0D 07 00 00",
    "00 08 00 00",
    "02 08 00 00",
    "05 08 00 00",
    "07 08 00 00",
    "0A 08 00 00",
    "0C 08 00 00",
    "0F 08 00 00",
    "02 09 00 00",
    "04 09 00 00",
    "07 09 00 00",
    "09 09 00 00",
    "0C 09 00 00",
    "0E 09 00 00",
    "01 0A 00 00",
    "03 0A 00 00",
    "06 0A 00 00",
    "09 0A 00 00",
    "0B 0A 00 00",
    "0E 0A 00 00",
    "00 0B 00 00",
    "03 0B 00 00",
    "05 0B 00 00",
    "08 0B 00 00",
    "0B 0B 00 00",
    "0D 0B 00 00",
    "00 0C 00 00",
    "02 0C 00 00",
    "05 0C 00 00",
    "07 0C 00 00",
    "0A 0C 00 00",
    "0C 0C 00 00",
    "0F 0C 00 00",
    "02 0D 00 00",
    "04 0D 00 00",
    "07 0D 00 00",
    "09 0D 00 00",
    "0C 0D 00 00",
    "0E 0D 00 00",
    "01 0E 00 00",
    "03 0E 00 00",
    "06 0E 00 00",
    "09 0E 00 00",
    "0B 0E 00 00",
    "0E 0E 00 00",
    "00 0F 00 00",
    "03 0F 00 00",
    "05 0F 00 00",
    "08 0F 00 00",
    "0B 0F 00 00",
    "0D 0F 00 00",
    "00 00 01 00"
}

local negativeNumbers = {
    "0E 0F 0F 0F",
    "0B 0F 0F 0F",
    "09 0F 0F 0F",
    "06 0F 0F 0F",
    "04 0F 0F 0F",
    "01 0F 0F 0F",
    "0E 0E 0F 0F",
    "0C 0E 0F 0F",
    "09 0E 0F 0F",
    "07 0E 0F 0F",
    "04 0E 0F 0F",
    "02 0E 0F 0F",
    "0F 0D 0F 0F",
    "0D 0D 0F 0F",
    "0A 0D 0F 0F",
    "07 0D 0F 0F",
    "05 0D 0F 0F",
    "02 0D 0F 0F",
    "00 0D 0F 0F",
    "0D 0C 0F 0F",
    "0B 0C 0F 0F",
    "08 0C 0F 0F",
    "05 0C 0F 0F",
    "03 0C 0F 0F",
    "00 0C 0F 0F",
    "0E 0B 0F 0F",
    "0B 0B 0F 0F",
    "09 0B 0F 0F",
    "06 0B 0F 0F",
    "04 0B 0F 0F",
    "01 0B 0F 0F",
    "0E 0A 0F 0F",
    "0C 0A 0F 0F",
    "09 0A 0F 0F",
    "07 0A 0F 0F",
    "04 0A 0F 0F",
    "02 0A 0F 0F",
    "0F 09 0F 0F",
    "0D 09 0F 0F",
    "0A 09 0F 0F",
    "07 09 0F 0F",
    "05 09 0F 0F",
    "02 09 0F 0F",
    "00 09 0F 0F",
    "0D 08 0F 0F",
    "0B 08 0F 0F",
    "08 08 0F 0F",
    "05 08 0F 0F",
    "03 08 0F 0F",
    "00 08 0F 0F",
    "0E 07 0F 0F",
    "0B 07 0F 0F",
    "09 07 0F 0F",
    "06 07 0F 0F",
    "04 07 0F 0F",
    "01 07 0F 0F",
    "0E 06 0F 0F",
    "0C 06 0F 0F",
    "09 06 0F 0F",
    "07 06 0F 0F",
    "04 06 0F 0F",
    "02 06 0F 0F",
    "0F 05 0F 0F",
    "0D 05 0F 0F",
    "0A 05 0F 0F",
    "07 05 0F 0F",
    "05 05 0F 0F",
    "02 05 0F 0F",
    "00 05 0F 0F",
    "0D 04 0F 0F",
    "0B 04 0F 0F",
    "08 04 0F 0F",
    "05 04 0F 0F",
    "03 04 0F 0F",
    "00 04 0F 0F",
    "0E 03 0F 0F",
    "0B 03 0F 0F",
    "09 03 0F 0F",
    "06 03 0F 0F",
    "04 03 0F 0F",
    "01 03 0F 0F",
    "0E 02 0F 0F",
    "0C 02 0F 0F",
    "09 02 0F 0F",
    "07 02 0F 0F",
    "04 02 0F 0F",
    "02 02 0F 0F",
    "0F 01 0F 0F",
    "0D 01 0F 0F",
    "0A 01 0F 0F",
    "07 01 0F 0F",
    "05 01 0F 0F",
    "02 01 0F 0F",
    "00 01 0F 0F",
    "0D 00 0F 0F",
    "0B 00 0F 0F",
    "08 00 0F 0F",
    "05 00 0F 0F",
    "03 00 0F 0F",
    "00 00 0F 0F"
}

function verifyFloat2Nibbles(value, expectedMemBlock)
    local temp = string.upper(float2nibbles(value):toHexString(1))
    assert(expectedMemBlock == temp, 
        string.format("Incorrect result for %.2f, expected %s, got %s", value, expectedMemBlock, temp))
end

for k,v in pairs(positiveNumbers) do
    verifyFloat2Nibbles(k / 100, v)
end

for k,v in pairs(negativeNumbers) do
    verifyFloat2Nibbles((k / 100) * -1, v)
end
函数float2nibbles(值)
本地半字节=内存块(4,真)
--检索要转换的给定值的整数部分和小数部分
局部整数,fract=math.modf(math.abs(value))
--计算整数部分的值(最后两个半字节)
局部bi=大整数(整数)
如果值<0,则
--此变量有时添加到MS半字节的负转换中
本地lsAdd=1
如果整数=0,则
lsAdd=0
结束
半字节:setByte(2,bit.band(bit.bnot(bi:getBitRangeAsInt(0,4))+lsAdd,0xF))
半字节:setByte(3,bit.band(bit.bnot(bi:getBitRangeAsInt(4,4)),0xF))
其他的
半字节:setByte(2,bit.band(bi:getBitRangeAsInt(0,4),0xF))
半字节:setByte(3,bit.band(bi:getBitRangeAsInt(4,4),0xF))
结束
--计算分数的值(前两个半字节)
局部余数=分形
本地prev=0
对于i=1,2 do
余数=余数*16
--余数的组成部分
局部d=math.modf(余数)
如果值<0且分数=0,则
本地lsAdd=1
如果分形=0或i==1,则
lsAdd=0
结束
控制台(string.format(“lsAdd%d”,lsAdd))
半字节:setByte(2-i,bit.band(bit.bnot(d)+lsAdd,0xF))
其他的
半字节:setByte(2-i,位带(d,0xF))
结束
控制台(string.format(“fract%d=%d,%.2f”,i,d,余数))
剩余=剩余
余数=余数-d
结束
--出于某种原因,当LS半字节应该增加第二个半字节的值时,此增量会有所帮助
如果半字节:getByte(0)==0且半字节:getByte(1)~=0且值<0,则
控制台(string.format(“奇怪增量{%d%d}”,半字节:getByte(0),半字节:getByte(1)))
半字节:setByte(1,半字节:getByte(1)+1)
结束
--这个数据的精度是一个字节,但显然他们似乎使用了第三个增量来检查舍入
余数=余数*16
控制台(string.format(“最终余数%.2f”,余数))
如果math.abs(余数-剩余数)>0.001,余数>14,则
控制台(string.format(“溢出->%.2f(%.2f)”,余数,剩余)
如果值<0,则
半字节:setByte(0,半字节:getByte(0)-1)
其他的
半字节:setByte(0,半字节:getByte(0)+1)
结束
结束
控制台(string.format(“%.2f:整数部分%s(%s),fract%.2f”,值,位.tohex(整数,2),半字节:toHexString(1),fract))
返回小口
结束
局部正枚举数={
"02 00 00 00",
"05 00 00 00",
"07 00 00 00",
“0A 00 00”,
“0C 00 00”,
“0F 00 00”,
"02 01 00 00",
"04 01 00 00",
"07 01 00 00",
"09 01 00 00",
“0C 01 00”,
“0E 01 00”,
"01 02 00 00",
"03 02 00 00",
"06 02 00 00",
"09 02 00 00",
“0B 02 00 00”,
“0E 02 00”,
"00 03 00 00",
"03 03 00 00",
"05 03 00 00",
"08 03 00 00",
“0B 03 00 00”,
“0D 03 00 00”,
"00 04 00 00",
"02 04 00 00",
"05 04 00 00",
"07 04 00 00",
“0A0400”,
“0C 04 00”,
“0F 04 00”,
"02 05 00 00",
"04 05 00 00",
"07 05 00 00",
"09 05 00 00",
“0C 05 00”,
“0E 05 00”,
"01 06 00 00",
"03 06 00 00",
"06 06 00 00",
"09 06 00 00",
“0B0600”,
“0E 06 00”,
"00 07 00 00",
"03 07 00 00",
"05 07 00 00",
"08 07 00 00",
“0B070000”,
“0D 07 00”,
"00 08 00 00",
"02 08 00 00",
"05 08 00 00",
"07 08 00 00",
“0A080000”,
“0C 08 00”,
“0F 08 00”,
"02 09 00 00",
"04 09 00 00",
"07 09 00 00",
"09 09 00 00",
“0C 09 00”,
“0E 09 00”,
“01 0A 00 00”,
“030A000”,
“060A000”,
“090A000”,
“0B 0A 00 00”,
“0E 0A 00 00”,
“00 0B 00 00”,
“03 0B 00 00”,
“05 0B 00 00”,
“08 0B 00 00”,
“0B 0B 00 00”,
“0D 0B 00 00”,
“00 0C 00 00”,
“02 0C 00”,
“05 0C 00”,
“07 0C 00”,
“0A 0C 00 00”,
“0C 0C 00 00”,
“0F 0C 00 00”,
“02 0D 00 00”,
“04 0D 00 00”,
“07 0D 00 00”,
“09 0D 00 00”,
“0C 0D 00 00”,
“0E 0D 00 00”,
“01 0E 00 00”,
“03 0E 00 00”,
“06 0E 00 00”,
n2a = {[0]='0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}

function f2h (f)
    -- TODO should range check f
    local scaledf = f * 256 -- move binary point 8 bits right
    -- TODO optionally you could also round scaledf here
    local scaledi = math.modf(scaledf) -- integer part
    -- convert to nibbles
    local scalediparts = { (0xf & scaledi),
                           (0xf & (scaledi >> 4)),
                           (0xf & (scaledi >> 8)),
                           (0xf & (scaledi >> 12)) }
    -- output in hex
    print(n2a[scalediparts[1]], n2a[scalediparts[2]], n2a[scalediparts[3]], n2a[scalediparts[4]])
    -- return the nibbles
    return scalediparts
end
> f2h(-0.01)
e   f   f   f
table: 0x7feaf9d06390
> f2h(-0.94)
0   1   f   f
table: 0x7feaf9e009a0
> f2h(0.01)
2   0   0   0
table: 0x7feaf9d06410
> 
function float2nibbles(value)
   local nibbles = MemoryBlock(4, true)
   local n = math.floor(math.abs(value)*256 + 0.13)
   n = value < 0 and 0x10000 - n or n
   for pos = 0, 3 do
      nibbles:setByte(pos, n%16)
      n = math.floor(n/16)
   end
   return nibbles
end