Limitations of the Number Type in JavaScript

September 15, 2021 Digital Experience

You don’t want any errors in your commercial or Scientific applications, do you?

In Javascript, the number type is used to represent all numbers like integers and decimals (123 or 123.45). But the underlying system representation of these numbers has an impact on the quality of your computations.

In this blog, we will see why JavaScript numbers are not necessarily suitable for commercial and scientific applications.

In a follow-up blog, we will see a solution using decimals support.

Background Information on Numbers in JavaScript

According to the ECMAScript standard, there is only one number type in JavaScript: the double-precision 64-bit binary format IEEE 754 value.

The 64 bits are used like this: 1 bit for sign,11 bits for exponent and 53 bits for significant digits.

Unlike some other languages, there is no specific type for integers. Starting with ECMAScript 2015, one can check if a number is in the double-precision floating-point number range using Number.isSafeInteger() as well as Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER.

Beyond this range, integers in JavaScript are not safe anymore and will be a double-precision floating point approximation of the value. We will see below some examples of this.

Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_typ

Specific Limitations

Because all numbers in JavaScript are implemented with floating point numbers, we have the following issues which could be detrimental to commercial or scientific applications:

  • Incorrect results with inexact numbers
  • Float computations are not deterministic
  • Very large or very small numbers cannot be processed, in particular when using Integers

In the next sections, we will go into detailed explanations for each of these issues.

Incorrect results with inexact numbers

The issue is that some floats do not have an exact representation. This leads to incorrect results and results that cannot be compared with certainty. Another way to put it, float numbers can only approximate decimal numbers that are commonly used for many commercial purposes.

At this point, you may be wondering what I am really talking about. Let’s look at a simple example:

Well, in JavaScript, 0.1 + 0.2 is NOT equal to 0.3.

Try this in a browser console: (to open the console for example with Google Chrome, type CRTL Shift J on Windows/Linux or Command+Option+J on Mac—see here).

console: console.log(0.1)

Output: 0.1

console: console.log(0.2)

Output: 0.2

console: console.log(0.1+0.2)

Output: 0.30000000000000004

The reason is that 0.1 has the following representation as a double: 0.1000000000000000055511151231257827021181583404541015625

So, you can imagine how repeating this kind of precision errors over lots of transactions could result in unacceptable financial results (million dollars a year differences on some transactions).

Note: Only dyadic numbers have an exact representation. You can check here and also here for more info.

Here is a tool to check if a number has an inexact representation as a float.

Float computations are not deterministic

Float computations are not deterministic (they produce different results) across machine architecture, compiler versions, etc. (Read this for issues encountered by game programmers).

This could potentially lead to different results when run on client side where the devices from cell phone to tablets to desktop run different OSes, hardware CPUs and floating point accelerators.

I haven’t personally run into this, and would be curious to know if you have. Please leave a note in the comments section if you ran into this issue.

Very large numbers cannot be processed

In the case of Integers, we are limited on both the positive and negative side. JavaScript defines constants for the limits: Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER.

console.log(Number.MAX_SAFE_INTEGER) produces 9007199254740991

console.log(Number.MIN_SAFE_INTEGER) produces -9007199254740991

Here is an example of errors you could get into:

Number.MAX_SAFE_INTEGER + 1: 9007199254740992 → correct.

Number.MAX_SAFE_INTEGER + 2: 9007199254740992 → clearly incorrect.

When doing any operations on your numbers, you can use Number.isSafeInteger() to verify that you have not exceeded the range.

Conclusion

In conclusion, when dealing with commercial or scientific applications, JavaScript developers need to carefully consider the limitations of the built-in number type.

In a follow-up blog, we will see how one can use a decimal library to minimize the issues outlined here.

Thierry Ciot

Thierry Ciot is a Software Architect on the Corticon Business Rule Management System. Ciot has gained broad experience in the development of products ranging from development tools to production monitoring systems. He is now focusing on bringing Business Rule Management to Javascript and in particular to the serverless world where Corticon will shine. He holds two patents in the memory management space.

Read next Decimals With No Limitations in JavaScript