在Lua中使用32位按位运算比较带符号的64位数

时间:2016-02-18 17:52:36

标签: lua redis

我在Redis上使用Lua并希望比较两个带符号的64位数字,这些数字存储在两个8字节/字符串中。

如何使用Redis中提供的库比较它们?  http://redis.io/commands/EVAL#available-libraries

我想知道>/<==支票。我认为这可能涉及为每个64位int拉两个32位数字,并对这些数字做一些聪明的数学,但我不确定。

我有一些代码可以使它不那么抽象。 a0a1b0b1都是32位数字,用于表示msb&amp;两个64位有符号int 64s的lsb:

-- ...
local comp_int64s = function (a0, a1, b0, b1)
    local cmpres = 0
    -- TOOD: Real comparison
    return cmpres
end
local l, a0, a1, b0, b1
a0, l = bit.tobit(struct.unpack("I4", ARGV[1]))
a1, l = bit.tobit(struct.unpack("I4", ARGV[1], 5))
b0, l = bit.tobit(struct.unpack("I4", blob))
b1, l = bit.tobit(struct.unpack("I4", blob, 5))
print("Cmp result", comp_int64s(a0, a1, b0, b1))

编辑:添加了代码

2 个答案:

答案 0 :(得分:2)

我提出了一种看起来很有效的方法。这有点难看。

第一步是将前32位比作2恭维# MSB符号位保持不变,因此数字保持正确的关系

-1  —> -1
0 —> 0
9223372036854775807 = 0x7fff ffff ffff ffff -> 0x7ffff ffff = 2147483647

因此,除非它们相等,否则返回MSB的结果,然后需要检查LSB。

我有一些案例可以确定一些模式:

-1 = 0xffff ffff ffff ffff
-2 = 0xffff ffff ffff fffe
32 bit is:
-1 -> 0xffff ffff = -1
-2 -> 0xffff fffe = -2
-1 > -2 would be like -1 > -2 : GOOD

8589934591 = 0x0000 0001 ffff ffff
8589934590 = 0x0000 0001 ffff fffe
32 bit is:
8589934591 -> ffff ffff = -1
8589934590 -> ffff fffe = -2
8589934591 > 8589934590 would be -1 > -2 : GOOD

MSB上的符号位无关紧要b / c负数与它们之间的正数之间具有相同的关系。例如,无论符号位如何,lsb值为0xff&gt; 0xfe,永远。

如果低32位的MSB不同,该怎么办?

0xff7f ffff 7fff ffff = -36,028,799,166,447,617
0xff7f ffff ffff ffff = -36,028,797,018,963,969
32 bit is:
-..799.. -> 0x7fff ffff = 2147483647
-..797.. -> 0xffff ffff = -1
-..799.. < -..797.. would be 2147483647 < -1 : BAD!

所以我们需要忽略低32位的符号位。而且由于无论符号如何,LSB的关系都是相同的,只需使用即可 最低32位无符号适用于所有情况。

这意味着我希望为MSB签名并为LSB签名 - 因此将I4更改为i4以获取LSB。同时制作大端官员并使用'&gt;'在struct.unpack调用:

-- ...
local comp_int64s = function (as0, au1, bs0, bu1)
    if as0 > bs0 then
        return 1
    elseif as0 < bs0 then
        return -1
    else
        -- msb's equal comparing lsbs - these are unsigned
        if au1 > bu1 then
            return 1
        elseif au1 < bu1 then
            return -1
        else
            return 0
        end
    end
end
local l, as0, au1, bs0, bu1
as0, l = bit.tobit(struct.unpack(">i4", ARGV[1]))
au1, l = bit.tobit(struct.unpack(">I4", ARGV[1], 5))
bs0, l = bit.tobit(struct.unpack(">i4", blob))
bu1, l = bit.tobit(struct.unpack(">I4", blob, 5))
print("Cmp result", comp_int64s(as0, au1, bs0, bu1))

答案 1 :(得分:1)

比较是一个简单的字符串比较s1 == s2

大于的时间是 s1 == s2i1 < i2

小于是真正的工作。 string.byte允许将单个字节设为unsigned char。在无符号整数的情况下,您只需要检查字节向下:b1==b2 - &gt;检查下一个字节;通过所有字节 - &gt; false (等于); b1>b2 - &gt; false (大于); b1<b2 - &gt;的即可。签名需要更多步骤:首先检查符号位(最上面的字节> 127)。如果设置符号1但不设置符号2,则整数1为负但不是整数2 - >的即可。相反的情况显然会导致错误。当两个符号相等时,您可以进行无符号处理。

当您可以将更多字节打包到整数时,它也可以,但您必须调整符号位检查。当你有LuaJIT时,可以使用 ffi 库将字符串转换为字节数组到int64。