2011-10-15 41 views
3

是一個真正的64位有符號整數的MongoDB的NumberLong真的64位?MongoDB的NumberLong只有54位簽名?

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位有符號整數。

這是爲什麼?
我做錯了什麼?從蒙戈外殼

樣品:

> 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

Math.pow最有可能運行在double秒。整數被強制漂浮,在2^54時,雙精度數字在1的位置失去分辨率。在您轉換回整數類型時,信息已經丟失。

使用左移<<或重複乘法得到可比較的結果嗎?

+0

你對浮子尾數的想法會解釋一切。不幸的是,左移整數僅適用於32位有符號,並且重複的乘法給出了與上述相同的輸出。 – fsto

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本身。檢查了這一點,對於example-- $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 } 

絕對值得記住。

相關問題