MongoDB的数字长度真的是64位有符号整数真的是64位吗?
mongodb的numberlong被称为64位有符号整数,这意味着我们可以使用-2^63<=x<=2^63-1,其中x是numberlong。
但是,从数字长(x)中加1或减1不返回x<=-2^54或x>=2^54的预期值,但返回-2^53<=x<=2^53的正确值。
因此,最长的可靠数字似乎是54位有符号整数。
这是为什么?
我做错什么了吗?
Mongo外壳样本:

> NumberLong( Math.pow(2,54) )
NumberLong("18014398509481984")    // Expected
> NumberLong( Math.pow(2,54)-1 )
NumberLong("18014398509481984")    // **NOT** Expected
> NumberLong( -Math.pow(2,54) )
NumberLong("-18014398509481984")   // Expected
> NumberLong( -Math.pow(2,54)+1 )
NumberLong("-18014398509481984")   // **NOT** Expected

> NumberLong( Math.pow(2,53) )
NumberLong("9007199254740992")     // Expected
> NumberLong( Math.pow(2,53)-1 )
NumberLong("9007199254740991")     // Expected
> NumberLong( -Math.pow(2,53) )
NumberLong("-9007199254740992")    // Expected
> NumberLong( -Math.pow(2,53)+1 )
NumberLong("-9007199254740991")    // Expected

使用MongoDB 2.0.0

最佳答案

哇,真让人费解。很明显这里发生了某种舍入误差。

> NumberLong("18014398509481984")-NumberLong("1");
18014398509481984

> NumberLong("18014398509481984")-NumberLong("2");
18014398509481982

> NumberLong("18014398509481984")+NumberLong("1");
18014398509481984

> NumberLong("18014398509481984")+NumberLong("2");
18014398509481984

> NumberLong("18014398509481984")+NumberLong("3");
18014398509481988

这可能是运行shell的javascript引擎出了问题,而不是mongodb本身。看看这个,例如--$inc工作正常:
> db.test.insert({twoTo54:NumberLong("18014398509481984")});
> db.test.update({},{$inc:{twoTo54:NumberLong("1")}});
> db.test.find();
{ "_id" : ObjectId("4f204847756aa806028abce1"), "twoTo54" : NumberLong("18014398509481985") }
> db.test.update({},{$inc:{twoTo54:NumberLong("1")}});
> db.test.find();
{ "_id" : ObjectId("4f204847756aa806028abce1"), "twoTo54" : NumberLong("18014398509481986") }
> db.test.update({},{$inc:{twoTo54:NumberLong("1")}});
> db.test.find();
{ "_id" : ObjectId("4f204847756aa806028abce1"), "twoTo54" : NumberLong("18014398509481987") }

不过,你得小心。如果只使用普通文本1,它会将类型转换为一个数字,然后该数字会打断$inc
> db.test.update({},{$inc:{twoTo54:1}});
> db.test.find();
{ "_id" : ObjectId("4f204847756aa806028abce1"), "twoTo54" : 18014398509481988 }
> db.test.update({},{$inc:{twoTo54:1}});
> db.test.find();
{ "_id" : ObjectId("4f204847756aa806028abce1"), "twoTo54" : 18014398509481988 }

即使你用$inc返回NumberLong("1"),它仍然是坏的:
> db.test.update({},{$inc:{twoTo54:NumberLong("1")}});
> db.test.find();
{ "_id" : ObjectId("4f204847756aa806028abce1"), "twoTo54" : 18014398509481988 }

一定要记住。

10-07 13:21