[SERVER-24802] Database store a value different to the one provided as 64 bits long integer Created: 25/Jun/16  Updated: 21/Aug/17  Resolved: 26/Jun/16

Status: Closed
Project: Core Server
Component/s: Internal Client, Internal Code
Affects Version/s: 3.2.7
Fix Version/s: None

Type: Bug Priority: Critical - P2
Reporter: TrustworthySystems [X] Assignee: Unassigned
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
related to SERVER-2477 Shell is displaying some numbers in a... Closed
related to SERVER-7812 NumberLong(max_of_int64) returns wron... Closed
is related to SERVER-30729 NumberLong compare with Number Closed
Operating System: ALL
Steps To Reproduce:

In a MongoDB Linux installation, following the Instructions at MongoDB Docs
Ref: http://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/

In Linux shell run the MongoDB shell client:

/usr/bin/mongo
MongoDB shell version: 3.2.7
connecting to: test
>

In the MongoDB shell client:

use integers
 
db.createCollection("sequences", {
   validator:
   {
      seq: { $type: "long" }
   },
   validationLevel: "strict",
   validationAction: "error"
})
 
db.sequences.insert(
   {  _id: "Seq1", seq: NumberLong(9223372036854775804) }
)
 
db.sequences.find()

You can drop the collection and restart with a different number:

db.sequences.drop()

Here is a command line running sample:

root@localhost:/# /usr/bin/mongo
MongoDB shell version: 3.2.7
connecting to: test
>
> use integers
switched to db integers
>
> db.createCollection("sequences", {
...    validator:
...    {
...       seq: { $type: "long" }
...    },
...    validationLevel: "strict",
...    validationAction: "error"
... })
{ "ok" : 1 }
>
> db.sequences.insert(
...    {  _id: "Seq1", seq: NumberLong(9223372036854775804) }
... )
WriteResult({ "nInserted" : 1 })
>
> db.sequences.find()
{ "_id" : "Seq1", "seq" : NumberLong("-9223372036854775808") }
>
>

Participants:

 Description   

Please, reroute me if this has a workaround for 64 bits, data handling (can't afford bits modifications by the database, or the database interface)

When using the mongo shell client in Linux, storing a 64 bits long integer result in a stored value different in more than 60 bits.
Is unknown if the problem is a client error, a database error or a data handling error.

Storing .. 9223372036854775804 (0x7FFFFFFFFFFFFFFC)
Stored .. -9223372036854775808 (0x8000000000000000)
62 bits differs

Storing .. 4611686018427387900 (0x3FFFFFFFFFFFFFFC)
Stored ... 4611686018427387904 (0x4000000000000000)
61 bits differs

Storing .. 2305843009213693951 (0x1FFFFFFFFFFFFFFF)
Stored ... 2305843009213693952 (0x2000000000000000)
62 bits differs

Storing .. 1152921504606846975 (0x0FFFFFFFFFFFFFFF)
Stored ... 1152921504606846976 (0x1000000000000000)
61 bits differs

Storing ... 576460752303423487 (0x07FFFFFFFFFFFFFF)
Stored .... 576460752303423488 (0x0800000000000000)
60 bits differs

Storing ... 288230376151711743 (0x03FFFFFFFFFFFFFF)
Stored .... 288230376151711744 (0x0400000000000000)
59 bits differs

I manage to pin point the border of the problem, when the bit 52 is on, the minor bits appears to be rounded (This make match with the 53 bits of mantissa for the IEEE 754 64 bit double precision floating point), the maximum number assignable (in case of restart, with initialization) is: 9,007,199,254,740,991

Storing ...... 9007199254740991 (0x001FFFFFFFFFFFFF)
Stored ....... 9007199254740991 (0x001FFFFFFFFFFFFF)
NO bits differs



 Comments   
Comment by TrustworthySystems [X] [ 25/Jun/16 ]

I test with your suggestion and save the 64 bit integer correctly,
they has to be passed from text directly to 64 bit integer via
NumberLong(), it work with the whole number range:

"−9223372036854775808" , ... , "-1" , "0" , "1" , ... , "9223372036854775807"

managed as text.

obviously this is not an internal issue, but a middle-ware issue,
numbers with absolute values less than 9007199254740991,
can be use as plain numbers (avoid the string representation).

Comment by Max Hirschhorn [ 25/Jun/16 ]

Hi TrustworthySystems,

The representation for Number values in JavaScript is as a double-precision 64-bit binary format IEEE 754 value. This is required by the ECMAScript specification: http://www.ecma-international.org/ecma-262/6.0/#sec-terms-and-definitions-number-value.

The reason why you're observing a loss of precision in the value that was inserted is because you're passing a number that exceeds Number.MAX_SAFE_INTEGER to the NumberLong() constructor. More specifically, since 9223372036854775804 exceeds 2^53 - 1, the Number value cannot represent an integer exactly, so you end up with a loss of precision prior to calling the NumberLong() constructor itself.

What you can do instead is pass the number as a numeric string to the NumberLonger() constructor, i.e. do NumberLong("9223372036854775804"). This will avoid any conversion to a Number value that would result in a loss of precision.

Hope that helps,
Max

Generated at Thu Feb 08 04:07:27 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.