【问题标题】:redis lua bit overflowredis lua 位溢出
【发布时间】:2015-11-02 09:44:33
【问题描述】:

我正在使用 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位有符号整数)

我使用的是 64 位的 Linux,redis 也被编译为 64 位。 看起来像是位库的限制:

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

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

另一方面...

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

知道如何更好地克服这个问题吗?

附:有人会说将此逻辑移至客户端-但我不能。这件作品相当复杂,需要与数据密切合作

【问题讨论】:

标签: lua redis overflow


【解决方案1】:

好像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 位整数。

另一方面,如果您需要的所有按位运算都是lshiftrshift,则可以在普通 Lua 中编写这些函数:

local function lshift(n, b)
   return n * 2^b
end

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

【讨论】:

  • 关于使用简单数学进行轮班的好提示!允许我清除那些丑陋的低/高字实现,并使代码更快;)
猜你喜欢
  • 2023-03-04
  • 1970-01-01
  • 2011-06-21
  • 2012-04-02
  • 1970-01-01
  • 2012-02-21
  • 1970-01-01
  • 2012-03-24
  • 2023-02-23
相关资源
最近更新 更多