2016-08-12 16 views
1

私はLuaで浮動小数点から16進数への変換に苦労しています。私のアプリケーションは古いAkai S2000サンプラーと通信します。サンプラーは、2バイトのメッセージを4つのニブル値にコーディングします。ニブルは逆順になっているため、最も重要なニブルは最後です。値の小数部の2進符号化を使用する1つのパラメータがあります。 2つのMSニブルは値の整数部分を符号化するために使用され、LSニブルは2進小数部分を符号化するために使用される。浮動小数点値を16進数に変換する

このディスカッションに基づいてhttps://bytes.com/topic/c/answers/219928-how-convert-float-hex私は与えられたパラメータ値からこれらのニブル値を生成するためにLuaアルゴリズムを実装し始めました。私はビット計算でそれほど強くないので、私は間違った方法で多くのことをやっていると思う。これらの値を計算し、私の愚かなif/elseハックを避けるためのより簡単な方法があるはずです。

マイナスの数字に対しては(下に貼り付けた)自分のコードは機能しますが、負の数値は非常に難しくなります。

私のテストでは、期待値のテーブルに追加しました。各テーブルは次のように動作します。

key = give value * 100 
value = expected outcome from my algorithm 

Ie. positiveNumbersテーブルの最初のエントリは0.01の入力値を表し、その値の期待される出力は02 00 00 00を含む4バイトのMemoryBlockです(最初の2バイトは端数を表し、最後の2バイトは整数部分を表します)。

現在、私のアルゴリズムは-0.94で失敗し、他の値を壊さずにハックすることはできません。

ビット計算の文字列があり、特に負の値を変換したときに起こったnoobの間違いを簡単に見ることができる人はいますか? 助けや指導をいただければ幸いです!

の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 

答えて

0
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 
+0

ありがとう!あなたのコードは素晴らしいです。しかし、0.13の価値の意味は何ですか?値の整数部分を表す16進数の数はどこで制御しますか? – pascalc

+0

'0.13'は' 0.12

0

一つの問題は、あなたが否定するとき、あなたは次の1つのニブルからのキャリーを伝播されていないということです。コードは見直しと修正が複雑すぎます。ここでやり直しです:

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 
> 

これはLuaの5.3ビット演算子を使用しています。 bitライブラリへの変換は簡単です。また、あなたの好みに合わせてprintステートメントと戻り値を変更する必要があります。

+0

私はビットライブラリを使用するようにコードを更新しました。残念ながら、アルゴリズムは失敗します:0.07、02 02 00 00 00、01 01 00 00の結果が不正です。 – pascalc

+0

はい、Egorのソリューションにはあなたのテーブルで動作させるための魔法の '+ 0.13'があります。これは私がコメントで述べた丸めです。 0.13/256は0.005であることに注意してください。 –

関連する問題