Redis Lua 比特溢出

3

我正在使用redis lua,并需要在一个字段上执行位运算逻辑,该字段最多有53位(redis有序集分数整数部分的默认长度)

但似乎我没有运气:

127.0.0.1:6379> eval 'return bit.lshift(1, 30) ' 0
(integer) 1073741824
127.0.0.1:6379> eval 'return bit.lshift(1, 31) ' 0
(integer) -2147483648

看起来 bit.* 只能在 30 位上操作,然后就会溢出(32 位有符号整数)

我正在使用 Linux 64 位系统,并且 redis 也是编译为 64 位的。 似乎这是 bit 库的一个限制:

http://bitop.luajit.org/api.html

请注意,所有位运算都返回带符号的 32 位数字(原理)。 默认情况下,这些数字将显示为带符号的十进制数。

另一方面...

eval 'return math.pow(2, 53) ' 0
(integer) 9007199254740992

你有什么更好的方法来解决这个问题吗?

P.S. 有人会说将此逻辑移到客户端,但我不能这样做。这段代码相当复杂,并且需要与数据密切配合工作。


好的,我找到了这个:https://dev59.com/X07Sa4cB1Zd3GeqP5KFn#7333595 纯粹糟糕而且慢,但看起来redis让我别无选择 :( - let4be
1
对于那些有兴趣的人,附上 Redis 问题链接:https://github.com/antirez/redis/issues/2843 - let4be
1个回答

2
“似乎 bit.* 只能在30位上运行,然后就会溢出(32位有符号整数)。”
并不完全正确。LuaJIT的BitOp可以在32位有符号整数上运行。这就是为什么2^31是一个负数的原因。 BitOp文档解释说之所以使用有符号int32而不是无符号是因为架构兼容性问题:
“将结果类型定义为无符号数字将不安全跨平台。因此,所有位操作都被定义为返回有符号32位数字范围内的结果。”

http://bitop.luajit.org/semantics.html

有时候在将位运算结果与常数进行比较时可能会出现麻烦。在这种情况下,需要使用 bit.tobit() 对常数进行规范化处理。例如:
> = bit.lshift(1, 31) == 2147483648
false
> = bit.lshift(1, 31) == bit.tobit(2147483648)
true

无论如何,LuaJIT的BitOp模块仅限于32位整数。
另一方面,如果你所需的所有位运算都是lshift和rshift,那么可以在普通Lua中编写这些函数。
local function lshift(n, b)
   return n * 2^b
end

local function rshift(n, b)
   return n / 2^b
end

很好的提示关于使用简单的数学来进行位移!这使我能够清除那些丑陋的低/高字实现,也让代码运行更快 ;) - let4be

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接