【问题标题】:Comparing signed 64 bit number using 32 bit bitwise operations in Lua在 Lua 中使用 32 位按位运算比较有符号的 64 位数
【发布时间】:2016-05-31 01:19:28
【问题描述】:

我在 Redis 上使用 Lua,想比较两个有符号的 64 位数字,它们存储在两个 8 字节/字符串中。

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

我想知道>/<== 支票。我认为这可能涉及为每个 64 位 int 提取两个 32 位数字,并对它们进行一些巧妙的数学运算,但我不确定。

我有一些代码可以减少抽象。 a0a1b0b1 都是 32 位数字,用于表示两个 64 位有符号 int 64 的 msb 和 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))

编辑:添加代码

【问题讨论】:

    标签: lua redis


    【解决方案1】:

    我想出了一个看起来可行的方法。虽然有点丑。

    第一步是将前 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 负数之间的关系与正数相同。例如,无论符号位如何,0xff > 0xfe 的 lsb 值总是如此。

    如果低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 未签名 - 所以将 LSB 的 I4 更改为 i4。还使大端正式并在 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))
    

    【讨论】:

      【解决方案2】:

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

      大于是当s1 == s2i1 &lt; i2时。

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

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

      【讨论】:

        猜你喜欢
        • 2011-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-19
        • 2018-01-05
        • 2011-05-13
        相关资源
        最近更新 更多