MongoDB的NumberLong只有54位签名?

发布于 12-09 17:57 字数 1111 浏览 0 评论 0原文

MongoDB 的 NumberLong 真的是 64 位有符号整数吗?真的是 64 位吗?

MongoDB 的 NumberLong 据说是一个 64 位有符号整数,这意味着我们可以使用 -2^63 <= x <= 2^63-1,其中 x 是一个 NumberLong。 但是,对 NumberLong(x) 加 1 或减 1 不会返回 x <= -2^54 或 x >= 2^54 的预期值,但会返回 -2^53 <= 的正确值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

Is a MongoDB's NumberLong really 64 bit signed integer really 64 bit?

MongoDB's NumberLong is said to be a 64 bit signed integer, which should mean we can play with -2^63 <= x <= 2^63-1, where x is a NumberLong.
However, adding 1 or subtracting 1 from a NumberLong(x) does not return the expected value for x <= -2^54 or x >= 2^54, but correct values are returned for -2^53 <= x <= 2^53.
The reliable NumberLong numbers therefor seem to be 54 bit signed integers.

Why is this?
Am I doing someting wrong?

Sample from the 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

Using MongoDB 2.0.0

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

溺深海2024-12-16 17:57:35

哇,这真是令人费解。显然这里发生了某种舍入错误。

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

即使您返回 $ incNumberLong("1"),它仍然损坏:

> db.test.update({},{$inc:{twoTo54:NumberLong("1")}});
> db.test.find();
{ "_id" : ObjectId("4f204847756aa806028abce1"), "twoTo54" : 18014398509481988 }

绝对要记住。

Wow, this is puzzling. Clearly there is some sort of rounding error happening here.

> 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

This is probably something wrong with the JavaScript engine that the shell runs in, rather than MongoDB itself. Check this out, for example--$inc works fine:

> 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") }

You have to be careful, though. If you use just a normal literal 1, it will convert the type to a Number, which then breaks the $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 }

And even if you go back to $inc with NumberLong("1"), it's still broken:

> db.test.update({},{$inc:{twoTo54:NumberLong("1")}});
> db.test.find();
{ "_id" : ObjectId("4f204847756aa806028abce1"), "twoTo54" : 18014398509481988 }

Definitely good to keep in mind.

山有枢2024-12-16 17:57:35

Math.pow 最有可能在 double 上运行。整数被强制转换为浮点数,并且在 2^54 处,双精度数字在 1 的位置失去分辨率。当您转换回整数类型时,该信息已经丢失。

使用左移 << 或重复乘法是否可以得到类似的结果?

Math.pow most likely operates on doubles. The integers are coerced to floats, and at 2^54, double precision numbers lose resolution at the 1's place. The information is already lost at the time you convert back to integer types.

do you get comparable results using left shift << or repeated multiplication?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文