0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Redis の Lua に int64 を渡す時は注意

Last updated at Posted at 2025-08-18

issue などをまとめる

(1)

127.0.0.1:6379> eval "return bit.rshift(5978328353,32)" 0 
(integer) 1683361057
127.0.0.1:6379> eval "return bit.lshift(32,32)" 0 
(integer) 32

int32 を超える数に対して bit 操作をするとエラーになる。

(2)

Lua 5.3 introduces the integer subtype, which uses 64-bit integer by default.

Lua 5.3 から int64 が導入されている。

The type number uses two internal representations, one called integer and the other called float.

Standard Lua uses 64-bit integers and double-precision (64-bit) floats, but you can also compile Lua so that it uses 32-bit integers and/or single-precision (32-bit) floats.

標準的な Lua は内部的に int64 と float64 を併用している。
ただし、設定によって、int32 や float32 を使う場合もある。

(3)

Lua 5.4 is not backwards compatible with 5.1, so if we wanna support it, we'll need to support both, and we eventually concluded that the shortcomings of 5.1 are not worth that complication.

redis はしばらく Lua 5.1 で行くと発言している。

検証

(1)

以下の検証結果を見ると、2^53(= 9007199254740992) 付近から正確な値ではなくなっているので、内部的に float64 を使っているのだろう。

127.0.0.1:6379> eval "return 9007199254740985" 0
(integer) 9007199254740985
127.0.0.1:6379> eval "return 9007199254740986" 0
(integer) 9007199254740986
127.0.0.1:6379> eval "return 9007199254740987" 0
(integer) 9007199254740987
127.0.0.1:6379> eval "return 9007199254740988" 0
(integer) 9007199254740988
127.0.0.1:6379> eval "return 9007199254740989" 0
(integer) 9007199254740989
127.0.0.1:6379> eval "return 9007199254740990" 0
(integer) 9007199254740990
127.0.0.1:6379> eval "return 9007199254740991" 0
(integer) 9007199254740991
127.0.0.1:6379> eval "return 9007199254740992" 0
(integer) 9007199254740992
127.0.0.1:6379> eval "return 9007199254740993" 0
(integer) 9007199254740992
127.0.0.1:6379> eval "return 9007199254740994" 0
(integer) 9007199254740994
127.0.0.1:6379> eval "return 9007199254740995" 0
(integer) 9007199254740996
127.0.0.1:6379> eval "return 9007199254740996" 0

参考

(2)

Lua 内では float64 で扱われているが、出力時には int64 に変換される。
int64 に変換したときに、int64 の最大値 9223372036854775807 を超えてしまうと、オーバーフローしてラップアラウンドされる。

参考

$ echo "2^63-1" | bc
9223372036854775807

(A)

「9223372036854775295 文字列 > float64(2^53-1 を超えているので正確ではない) > int64(9223372036854774784)」 のように変換される。

127.0.0.1:6379> eval 'return 9223372036854775295' 0
(integer) 9223372036854774784

(B)

「9223372036854775296 文字列 > float64(2^53-1 を超えているので正確ではない) > int64(-9223372036854775808)」 のように変換される。
int64 に変換時にオーバーフローしてラップアラウンドされる。

127.0.0.1:6379> eval 'return 9223372036854775296' 0
(integer) -9223372036854775808

結論

redis が利用している Lua 5.1 は、内部で float64 と int32 を併用している。
Redis はネイティブに int64 を扱えるが、Lua を使う時は注意が必要ということである。
例えば、以下のSDKの eval メソッドでは Lua を使うが、int64 でも引数として渡すことは可能だが、以下の点で注意が必要である。

  • 基本的には float64 であり、2^53-1 を超えたら、正確ではなくなる
  • bit.rshift() などの int32 を前提としているメソッドに、int32 の最大値を超えた数値を渡すと不正確な値になる
  • 最後に出力されるのは int64 なので、int64 の最大値を超えた float64 を出力しようとすると、オーバーフローしてラップアラウンドされる。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?