MongoDBの64bit整数型が思ったより小さかった
ご存じの様に、MongoDBの数値型(number)はfloat(64-bit) だ。
number ( 64-bit float) : double
- 指数部
- 52 bit(精度は53 bit)
- 仮数部
- 11 bit
- 符号
- 1 bit
なので0x20000000000001=2^53+1は桁溢れを起す。
> db.test.drop() true > db.test.save({i:0x1fffffffffffff}) > db.test.save({i:0x20000000000000}) > db.test.save({i:0x20000000000001}) > db.test.find({},{_id:0}) { "i" : 9007199254740991 } { "i" : 9007199254740992 } { "i" : 9007199254740992 }
NumberLong (64-bit integer) : int64_t ?
問題はコイツだ。
マニュアルには単に64-bit integerとしか書かれて無い。
しかし・・・
> db.test.drop() true > db.test.save({i:NumberLong(0x20000000000001)}) > db.test.find({},{_id:0}) { "i" : NumberLong("9007199254740992") }
おいおい、、53-bitで溢れてるじゃねーか!!
しかも
- 本来の64bit integer最大値0x7fffffffffffffffはマイナスで
- 少し小さいは0x7000000000000000はプラス!
- じゃあ符号ビットが違う所にあるのかと思いきやそうでもない・・・
> db.test.save({i:NumberLong(0x7fffffffffffffff)}) > db.test.save({i:NumberLong(0x7000000000000000)}) > db.test.save({i:NumberLong(0x6fffffffffffffff)}) > db.test.find({},{_id:0}) { "i" : NumberLong("-9223372036854775808") } { "i" : NumberLong("8070450532247928832") } { "i" : NumberLong("8070450532247928832") }
多分途中の処理のどこかでdoubleにしちゃってるんだろうな・・・
あとMongoDBの問題じゃなくてMongo shell の問題の可能性もある。