読者です 読者をやめる 読者になる 読者になる

中年engineerの独り言 - crumbjp

LinuxとApacheの憂鬱

NumberLong(64-bit integer) in MongoDB was smaller than I expected...

As you know, the default number type in MongoDB is 64-bit float.

number ( 64-bit float) : double
fraction
52-bit (Actually meaning 53-bit precision)
exponent
11-bit
sign
1-bit

So "0x20000000000001=2^53+1" will cause overflow.

> 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 ?

I found it difficult to understand the NumberLong type.

It seems like a normal 64-bit integer (int64_t) in manual.

But...

> db.test.save({i:NumberLong(0x20000000000001)})
> db.test.find({},{_id:0})
{ "i" : NumberLong("9007199254740992") }

Ops!!! Overflowed !!!!


本来の64bit integer最大値0x7fffffffffffffffはマイナスで
少し小さいは0x7000000000000000はプラス!
じゃあ符号ビットが違う所にあるのかと思いきやそうでもない・・・

Moreover,

  • Originally, 0x7fffffffffffffff must be the MAX 64-bit integer. But actually become negative value in MongoDB.
  • And, 0x7000000000000000 that is somewhat less than MAX become positive value...
  • I lost sight of the Sign bit... when I got negative value in 0x6fffffffffffffff.
> 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") }

I guess that It must be casted to floating point on the way to the result.
And this might not be the issue of the MongoDB but the issue of the Mongo Shell.