Everything about JavaScript numbers

*This is a work in progress*. *All code examples have been run on Node 8.11.5*

JavaScript, as specified in the ECMAScript standard, uses double-precision floating-point format numbers (specified in the
IEEE 754) for all arithmetics.
The *IEEE 754* can only represent safely numbers between `-(2`

and ^{53} - 1)`2`

.^{53} - 1

Quoting the Wikipedia:

An IEEE 754 format is a "set of representations of numerical values and symbols". A format may also include how the set is encoded.

The IEEE 754 double uses the format *binary64* (double-precision floating-point format).
This means JavaScript stores numbers in 64 bits. The fraction part is stored in bits 0 to 51.
The exponent part is stored in bits 52 to 62. The sign is stored in bit 63.

Quoting again the Wikipedia:

Floating point is used to represent fractional values, or when a wider range is needed than is provided by fixed point (of the same bit width), even if at the cost of precision.

Some numbers can't be exactly represented with binary numbers in the computer, that causes things like this to happen:

This is not just on JavaScript but any language the uses floating point format for numbers.

Integers (without decimal point or exponent notation) are accurate up to 15 digits, beyond this not all integer numbers can be represented accurately.

Here is a document (math heavy) with more info if you want to go deeper: What Every Computer Scientist Should Know About Floating-Point Arithmetic . And here is another deep dive: What Every JavaScript Developer Should Know About Floating Point Numbers . Also check How numbers are stored in JavaScript .

We have two types of zero (signed zero), negative and positive;

We'll see in the section for `Infinity`

how this results when doing a division by zero.

We can check for negative zero using division and a comparison to zero itself, taking advantage of positive/negative `Infinity`

:

If we try to convert negative or positive zero to a string we just get a '0':

Also if we try to search for negative/positive zero in arrays, since `indexOf`

uses `===`

we get the position
of either positive or negative:

Same for conditional operators (ordering):

JavaScript has only one number type: `Number`

.

All numbers in JavaScript are `floating-point`

.

`Number`

is a wrapper object, used like this:

When the argument can't be converted to number it returns `NaN`

. NaN is a value representing "Not a number".

A number created with the `Number`

constructor gives us an object:

This means we can't compare it with other numbers, since they are different types:

We can get the value using `valueOf`

:

When using the `==`

comparison operator we do get the expected result (since this is not type strict):

If we use two `Number`

objects we can't compare them this way:

To avoid this kind of issues we most of the times don't use wrapped Number objects, instead just use numbers.

`Number`

is a function:

Without the `new`

keyword (non-constructor context), `Number`

performs a type conversion.

Boolean value `true`

is converted to 1, and `false`

to 0:

`undefined`

is converted into `NaN`

`null`

is converted into zero:

Strings are parsed when possible, ignoring trailing and leading whitespace. Empty string is converted to zero.

For this, whitespace includes new lines, tabs, etc. For example:

Empty list is converted to zero:

If a list contains one item that is possible to convert to a number we get that number:

If our list has more than one item, or it is not possible to convert the first item into a number, we get NaN:

Empty objects and functions return NaN:

The reason behind all this is because of the process used to convert the parameter passed to `Number`

:

- Check if our object is a primitive
- Check the result of
`valueOf`

- Check the result of
`toString`

- Return NaN

In this case we have a valueOf:

In this case we are using the `toString`

method:

In the case of passing a date to Number, we get the milliseconds since midnight January 1, 1970 UTC,
value that is returned by the `valueOf`

method of the date instance,
and also the method `getTime`

.

When joining a number with a string, you might get something unexpected:

This is because in this case JavaScript is using the plus sign to mean *string concatenation*.

With subtraction tho, it converts the string into a number and then does the subtraction:

Since an empty list is converted into zero, if we add to an empty list we get something like this:

We have then to be careful what we are adding when using addition, we might get unexpected things.

In this case the `["2"]`

is causing all of our operation to be treated as a string concatenation.

Numbers can be written in different formats, like Hexadecimal (base 16) starting with `0x`

:

Octal (base 8) format starting with a leading `0`

:

Octal can also be written with a leading `0o`

:

Binary (base 2) format starting with a leading `0b`

:

Using the short e-notation. This notation indicates a number that should be multiplied by 10 raised to a
a power. For example, `1e9`

is one billion:

The e-notation can have negative numbers too:

Javascript converts any value with at least six zeros after the decimal point into e-notation.

Different formats are just for *representation* and can be used with other formats:

NaN is a value representing "Not a number". This function gives answer to the question: "Is this value, when coerced to a number, an IEEE-754 'NaN' value?". You can read more on NaN for floating point in Wikipedia.

`NaN`

is usually returned when `Math`

functions fail:

`isNaN`

checks if a value is NaN or not. This is useful since we can't rely on the
`==`

or `===`

operators to check against NaN. NaN is never equal to itself.

When called without a parameter (it is undefined) we get `true`

:

And of course NaN is a NaN:

Since NaN is never equal to NaN, we can't search for it in arrays:

NaN values are generated when arithmetic operations give us undefined or something that can't be represented as a number.

When we divide zero by itself, we get a NaN, this is because NaN is not the same as infinity, as we will see when we divide other numbers by zero.

As we will see later ECMAScript 2015 added the `isNaN`

method to Number instances.

Another way to check if a number is NaN is checking it against itself, taking advantage of the unique "never equal to itself" feature of NaN.

When used in arithmetic operations everything is NaN:

`Infinity`

is a read-only global value that represent infinity. The initial value of Infinity is `Number.POSITIVE_INFINITY`

.

Infinity is a number type:

When we divide a number by zero, we get Infinity:

If we do a negative zero division we get a negative Infinity, and with positive zero we get a positive Infinity:

Also in the case when we use `Math.pow`

with zero and a negative number:

If we multiply any number by Infinity we get Infinity:

If we subtract Infinity to a number we get a negative Infinity:

If you try to do a subtraction of Infinity to Infinity, you get NaN. Same for division:

Trying to add to infinity or to multiply will never give you anything different;

`Number.EPSILON`

`Number.MAX_SAFE_INTEGER`

`Number.MAX_VALUE`

`Number.MIN_SAFE_INTEGER`

`Number.MIN_VALUE`

`Number.NaN`

`Number.NEGATIVE_INFINITY`

`Number.POSITIVE_INFINITY`

`Number.isNaN()`

. This one is different than the global `isNaN`

function, since this one does not convert
the parameter to a number. This makes it safer to test against actual NaN, only values of type number that are NaN return true.

`Number.isFinite()`

. This one is also different to the global version of `isFinite`

since it does not
convert the parameter to a number. Only values of type number that are finite return true.

`Number.isInteger()`

`Number.isSafeInteger()`

`Number.parseFloat()`

. Parses the argument and returns a floating point number, if it can't convert it to float, it returns
`NaN`

.

`Number.parseInt()`

. Takes 2 parameters, first one is a string, if it is not a string it is converted to one (using `toString`

).
The second one is the `radix`

, usually the default is 10, but might change on implementations.
**Always** set the radix to avoid confusion.

`Number.prototype.toExponential()`

. Receives an option parameter to specify the number of digits after the decimal point. Returns a string, and
throws `RangeError`

if the parameter is too big/small, or `TypeError`

if invoked in something that is not a number.

`Number.prototype.toFixed()`

. Receives a parameter of the number of decimal points to show (between 0 and 20)
and returns a string with the specified decimal points. The number is rounded if necessary, and the fractional part padded with zeros for
the desired length.

`Number.prototype.toLocaleString()`

. Returns a string with a language sensitive representation of the number. Accepts two parameters
`locales`

(string with a BCP 47 language tag, like "hi"). And the second parameter an object with options localeMatcher, style, currency,
currencyDisplay, useGrouping, minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits, minimumSignificantDigits and
maximumSignificantDigits.

`Number.prototype.toPrecision()`

. Returns a string representing a Number object in fixed-point/exponential
notation, rounded if necessary, and the fractional part padded with zeros for the desired length.

`Number.prototype.toString()`

. Returns a string representing the number. Accepts a parameter `radix`

between 2 to 36 for the base to use.

`Number.prototype.valueOf()`

. Returns the *primitive* value of a number object.

As we noted before, it is recommended in JavaScript to NOT compare non-integers together, this is to avoid issues with imprecise numbers like in:

If we try to compare this with `0.3`

we get this:

Quoting the WikiBooks:

When a real number is rounded to the nearest floating point number, the machine epsilon forms an upper bound on the relative error.

Basically, we can use the upper bound to compare our values:

Made with by PR