## Number

Whenever you are handling numbers in any programming language you need to be aware of the idiosyncrasies of how the language handles numbers. Here are a few critical pieces of information about numbers in JavaScript that you should be aware of.

### Core Type

JavaScript has only one number type. It is a double-precision 64-bit `Number`. Below we discuss its limitations along with a recommended solution.

### Decimal

For those familiar with doubles / float in other languages, you would know that binary floating point numbers do not map correctly to Decimal numbers. A trivial (and famous) example with JavaScript's built in numbers is shown below:

``````console.log(.1 + .2); // 0.30000000000000004
``````

For true decimal math use `big.js` mentioned below.

### Integer

The integer limits represented by the built in number type are `Number.MAX_SAFE_INTEGER` and `Number.MIN_SAFE_INTEGER`.

``````console.log({max: Number.MAX_SAFE_INTEGER, min: Number.MIN_SAFE_INTEGER});
// {max: 9007199254740991, min: -9007199254740991}
``````

Safe in this context refers to the fact that the value cannot be the result of a rounding error.

The unsafe values are `+1 / -1` away from these safe values and any amount of addition / subtraction will round the result.

``````console.log(Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2); // true!
console.log(Number.MIN_SAFE_INTEGER - 1 === Number.MIN_SAFE_INTEGER - 2); // true!

console.log(Number.MAX_SAFE_INTEGER);      // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1);  // 9007199254740992 - Correct
console.log(Number.MAX_SAFE_INTEGER + 2);  // 9007199254740992 - Rounded!
console.log(Number.MAX_SAFE_INTEGER + 3);  // 9007199254740994 - Rounded - correct by luck
console.log(Number.MAX_SAFE_INTEGER + 4);  // 9007199254740996 - Rounded!
``````

To check safety you can use ES6 `Number.isSafeInteger`:

``````// Safe value
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER)); // true

// Unsafe value
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)); // false

// Because it might have been rounded to it due to overflow
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 10)); // false
``````

JavaScript will eventually get BigInt support. For now, if you want arbitrary precision integer math use `big.js` mentioned below.

### big.js

Whenever you use math for financial calculations (e.g. GST calculation, money with cents, addition etc) use a library like big.js which is designed for

• Perfect decimal math
• Safe out of bound integer values

Installation is simple:

``````npm install big.js @types/big.js
``````

Quick Usage example:

``````import { Big } from 'big.js';

export const foo = new Big('111.11111111111111111111');
export const bar = foo.plus(new Big('0.00000000000000000001'));

// To get a number:
const x: number = Number(bar.toString()); // Loses the precision
``````

Do not use this library for math used for UI / performance intensive purposes e.g charts, canvas drawing etc.

### NaN

When some number calculation is not representable by a valid number, JavaScript returns a special `NaN` value. A classic example is imaginary numbers:

``````console.log(Math.sqrt(-1)); // NaN
``````

Note: Equality checks don't work on `NaN` values. Use `Number.isNaN` instead:

``````// Don't do this
console.log(NaN === NaN); // false!!

// Do this
console.log(Number.isNaN(NaN)); // true
``````

### Infinity

The outer bounds of values representable in Number are available as static `Number.MAX_VALUE` and `-Number.MAX_VALUE` values.

``````console.log(Number.MAX_VALUE);  // 1.7976931348623157e+308
console.log(-Number.MAX_VALUE); // -1.7976931348623157e+308
``````

Values outside the range where precision isn't changed are clamped to these limits e.g.

``````console.log(Number.MAX_VALUE + 1 == Number.MAX_VALUE);   // true!
console.log(-Number.MAX_VALUE - 1 == -Number.MAX_VALUE); // true!
``````

Values outside the range where precision is changed resolve to special values `Infinity`/`-Infinity` e.g.

``````console.log(Number.MAX_VALUE + 10**1000);  // Infinity
console.log(-Number.MAX_VALUE - 10**1000); // -Infinity
``````

Of-course, these special infinity values also show up with arithmetic that requires it e.g.

``````console.log( 1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
``````

You can use these `Infinity` values manually or using static members of the `Number` class as shown below:

``````console.log(Number.POSITIVE_INFINITY === Infinity);  // true
console.log(Number.NEGATIVE_INFINITY === -Infinity); // true
``````

Fortunately comparison operators (`<` / `>`) work reliably on infinity values:

``````console.log( Infinity >  1); // true
console.log(-Infinity < -1); // true
``````

### Infinitesimal

The smallest non-zero value representable in Number is available as static `Number.MIN_VALUE`

``````console.log(Number.MIN_VALUE);  // 5e-324
``````

Values smaller than `MIN_VALUE` ("underflow values") are converted to 0.

``````console.log(Number.MIN_VALUE / 10);  // 0
``````

Further intuition: Just like values bigger than `Number.MAX_VALUE` get clamped to INFINITY, values smaller than `Number.MIN_VALUE` get clamped to `0`.