MongoDB的NumberLong真的是64位有符号整数吗64位?
MongoDB的NumberLong被称为64位有符号整数,这意味着我们可以使用-2 ^ 63&lt; = x&lt; = 2 ^ 63-1,其中x是NumberLong。 但是,从NumberLong(x)中加1或减1不会返回x&lt; = -2 ^ 54或x&gt; = 2 ^ 54的预期值,但会返回正确的值-2 ^ 53&lt; = x <= 2 ^ 53 可靠的NumberLong数字似乎是54位有符号整数。
为什么会这样?
我做错了什么?
来自mongo shell的示例:
> 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
答案 0 :(得分:2)
> 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 }
绝对要记住。
答案 1 :(得分:0)
Math.pow
最有可能在double
上运行。整数被强制浮动,并且在2 ^ 54,双精度数字在1的位置失去分辨率。在您转换回整数类型时,信息已经丢失。
您是使用左移<<
还是重复乘法获得可比较的结果?