TQ
dev.com

Blog about software development

Subscribe

JavaScript cannot handle 64 bit integers

30 Nov 2016 - by 'Maurits van der Schee'

JavaScript represents all numbers using IEEE-754 double-precision (64 bit) floating points. This is problematic for 64 bit integers, since this gives only gives you 53 bits of precision (the size of the mantissa). Bit operations are also only available for integer number up to 32 bits. Finally, the JSON exchange format does not support the IEEE-754 "NaN", "Infinity" and "-Infinity" values. So the only numbers you can freely use in JavaScript without the risk of data-loss are 32 bit integers.

Auto incrementing primary keys

When you are using 64 bit auto incrementing primary keys you are at risk. This is the data type 'bigint' in SQL Server and MySQL or 'bigserial' in PostgreSQL. Unless you are using NodeJS, you can correctly represent their value in a JSON object, but as soon as you interpret these values they lose precision. The simplest work-around is to represent these numbers as strings in your JSON. Alternatively you can switch to UUID primary keys, which have nice properties for distributed systems as an added benefit.

Bitwise operators

The bitwise operators 'AND', 'OR', 'NOT', 'XOR', '<<', '>>' and '>>>' will convert the operands to a true 32 bit integer before applying the operation. The 32 bit result of the operation will be stored in a double-precision floating point. This means you cannot apply these operators on any number that is bigger than 32 bits without losing data.

Special float values

The "NaN", "Infinity" and "-Infinity" floating point values are not supported in JSON. The obvious work-around is to send them as a string and interpret them using the JavaScript "parseFloat" function. This will correctly handle them which will reduces most of the problem to a technicality in practice. Nevertheless it is a good thing to be aware of.

How big is the integer problem?

Not very, as you can see below:

int64   fits any 18 digit number (63 bit + sign bit)
float64 fits any 15 digit number (53 bit mantissa)
int32   fits any  9 digit number (31 bit + sign bit)

... and we are not making a big fuss about signed or unsigned int64 either (allowing us either 18 or 19 digits), are we? A number of 15 digits is still a very very large number that you will not encounter very often.

Conclusion

The way numbers are handled is a bit strange, unexpected and certainly not pretty. This may sound alarming to you if you are used to more predictable languages (like Go or Java). On the other hand it will not lead to many problems in practice as long as you aware of these explicit inner workings. I hope this post has helped to create this awareness for you (it did for me).