# Why Are The Numbers In JavaScript So Strange?

Note: The knowledge of binary is needed to read this article.

Many JavaScript developers may have come across the strange phenomena of dealing with the numbers in JavaScript, such as:

``````> 0.1 + 0.2
0.30000000000000004

> 0.1 + 1 - 1
0.10000000000000009

> 0.1 * 0.2
0.020000000000000004

> Math.pow(2, 53)
9007199254740992

> Math.pow(2, 53) + 1
9007199254740992

> Math.pow(2, 53) + 3
9007199254740996``````

If you want to explore the reason, first of all, you need to figure out how numbers are encoded in JavaScript.

## 1. How Numbers Are Encoded In JavaScript?

The numbers in JavaScript, no matter they are integers, fractions, or positive or negative numbers, are all float numbers, which are stored in a binary format, in 8 bytes (64 bits).

A number (such as `12`, `0.12`, `-999`) occupies 8 bytes (64 bits) in memory and is stored in the way as follows:

1. `0 - 51`: fraction part (52 bits)
2. `52 - 62`: exponent part (11 bits)
3. `63`: sign bit (1 bit: 0 means the number is positive, 1 means the number is negative)

The sign bit is easy to understand and is used to indicate whether the number is positive or negative. And it has only 1 bit for two cases (0 for the positive number and 1 for the negative number).

The other two parts are the fraction part and the exponent part, which are used to calculate the absolute value of a number.

### 1.1 Formula for calculating absolute values

``````1: abs = 1.f * 2 ^ (e - 1023)             0 < e < 2047
2: abs = 0.f * 2 ^ (e - 1022)             e = 0, f > 0
3: abs = 0                                e = 0, f = 0
4: abs = NaN                              e = 2047, f > 0
5: abs = ∞ (infinity)                     e = 2047, f = 0``````
• It is a binary calculation formula, and the result is represented with `abs`, the fraction part is represented with `f`, and the exponent part is represented with `e`;
• `2 ^ (e - 1023)` represents the `e - 1023` power of `2`
• Since the fraction part occupies 52 bits, the value of `f` ranges from `00...00` (48 `0`'s are omitted in the middle) to `11...11` ( 48 `1`'s are omitted in the middle)
• Since the exponent part occupies 11 bits, the value of `e` ranges from `0` (`00000000000`) to `2047` (`11111111111`).

So:

• `1` is stored as: `1.00 * 2 ^ (1023 - 1023)``f = 0000..., e = 1023``...` represents 48 0's)
• 2 is stored as: `1.00 * 2 ^ (1024 - 1023)``f = 0000..., e = 1024``...` represents 48 0's)
• 9 is stored as: `1.01 * 2 ^ (1025 - 1023)``f = 0100..., e = 1025``...` represents 48 0's)
• 0.5 is stored as: `1.00 * 2 ^ (1022 - 1023)``f = 0000..., e = 1022``...` represents 48 0's)
• 0.625 is stored as: `1.01 * 2 ^ (1021 - 1023)``f = 0100..., e = 1021``...` represents 48 0's)

### 1.2 Range and boundary of absolute values

What can be seen from the above formula is:

#### 1.2.1 0 < e < 2047

When `0 < e < 2047`, the range of values ​​is from `f = 0, e = 1` to `f = 11...11, e = 2046` (48 1's are omitted in the middle)

The above means that the range is from `Math.pow(2, -1022)` to `~= Math.pow(2, 1024) - 1`(`～=` represents approximately equal)

Here, `~= Math.pow(2, 1024) - 1` is the value of `Number.MAX_VALUE`, which is the maximum value you can represent in JavaScript.

#### 1.2.2 `e = 0, f > 0`

When `e = 0, f > 0`, the range of values ​​is from `f = 00...01, e = 0` (48 0's are omitted in the middle) to `f = 11...11, e = 0` (48 1's are omitted in the middle)

The above means that the range is from: `Math.pow(2, -1074)` to `~= Math.pow(2, -1022)` (`～=` represents approximately equal)

Here, `Math.pow(2, -1074)` is the value of `Number.MIN_VALUE`, which is the minimum value (the absolute value) you can represent in JavaScript.

#### 1.2.3 e = 0, f = 0

It only represents the value of `0`, but there are `+0` and `-0` if you take with the sign bit.

However in the operation:

``````> +0 === -0
true``````

#### 1.2.4 e = 2047, f > 0

It only represents the value of `NaN`.

But in the operation:

``````> NaN == NaN
false

> NaN === NaN
false``````

#### 1.2.5 e = 2047, f = 0

This only represents the value of `∞` (infinity).

In the operation:

``````> Infinity === Infinity
true

> -Infinity === -Infinity
true``````

### 1.3 Maximum Safe Value Of Absolute Values

As you can see from the above, the maximum value that can be stored in 8 bytes is the value of `Number.MAX_VALUE`, which is `~= Math.pow(2, 1024) - 1`.

But the values are not safe: the numbers in the range from `1` to `Number.MAX_VALUE` are not continuous, but discrete.

For example: The values of `Number.MAX_VALUE - 1`, `Number.MAX_VALUE - 2` and so on ​​can't be formulated, thus they can't be stored.

So here comes the maximum safe value, `Number.MAX_SAFE_INTEGER`, which means that the numbers from `1` to `Number.MAX_SAFE_INTEGER` are continuous, so the numerical calculations in this range are safe.

You can get the value `111...11` (48 1's are omitted in the middle), ie `Math.pow(2, 53) - 1` when `f = 11...11, e = 1075` (48 1's are omitted in the middle).

Values ​​greater than `Number.MAX_SAFE_INTEGER：Math.pow(2, 53) - 1` are discrete.

For example: `Math.pow(2, 53) + 1`, `Math.pow(2, 53) + 3` can't be formulated and can't be stored in memory.

So it is the reason why you feel the code at the beginning of this article is so strange:

``````> Math.pow(2, 53)
9007199254740992

> Math.pow(2, 53) + 1
9007199254740992

> Math.pow(2, 53) + 3
9007199254740996``````

`Math.pow(2, 53) + 1` can't be formulated, so it can't be stored in memory. Thus you have to get another number which can be formulated as well as is closest. Here the obtained number is `Math.pow(2, 53)`, and it can be stored in memory then. This leads to distortion, so it is not safe.

### 1.4 Storage And Calculation Of Decimal Fractions

Only the decimal fractions that satisfies the condition of `m / (2 ^ n)` (`m, n` are integers) can be represented by the binary completely. The others can't be represented by the binary completely, and only can be represented by approaching the binary fraction infinitely..

(Note: `[2]` means binary)

``````0.5 = 1 / 2 = [2]0.1
0.875 = 7 / 8 = 1 / 2 + 1 / 4 + 1 / 8 = [2]0.111``````

Approximation of 0.3:

``````0.25 ([2]0.01) < 0.3 < 0.5 ([2]0.10)

0.296875 ([2]0.0100110) < 0.3 < 0.3046875 ([2]0.0100111)

0.2998046875 ([2]0.01001100110) < 0.3 < 0.30029296875 ([2]0.01001100111)

//... It'll calculate according to the formula until the 52 bits of the fractional part are filled, and then take the nearest number.
Storage for 0.3：[2]0.010011001100110011001100110011001100110011001100110011

(f = 0011001100110011001100110011001100110011001100110011, e = 1021)``````

What can be seen from the above is that most of the decimals are only approximations, and only a small part is the true value, so only the values ​​(the decimals that satisfy the condition of `m / (2 ^ n)`) from this small part can be compared directly, while the others can't be compared directly.

``````> 0.5 + 0.125 === 0.625
true

> 0.1 + 0.2 === 0.3
false``````

In order to compare two decimals safely, we can introduce `Number.EPSILON [Math.pow(2, -52)]` to compare floating point numbers.

``````> Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON
true``````

### 1.5 Maximum Reserved Digits For Decimals

It retains a maximum of 17 significant digits when JavaScript reads a number from memory.

``````> 0.010011001100110011001100110011001100110011001100110011
0.30000000000000000
0.3

> 0.010011001100110011001100110011001100110011001100110010
0.29999999999999993

> 0.010011001100110011001100110011001100110011001100110100
0.30000000000000004

> 0.0000010100011110101110000101000111101011100001010001111100
0.020000000000000004``````

## 2. Constants In The Number Object

### 2.1 Number.EPSILON

The difference between 1 and the smallest floating point number represented by Number and greater than 1.

``Math.pow(2, -52)``

It's used for safe comparison between floating point numbers.

### 2.2 Number.MAX_SAFE_INTEGER

The maximum safe value of the absolute value.

``Math.pow(2, 53) - 1``

### 2.3 Number.MAX_VALUE

The maximum value that js can represent (the maximum value that can be stored in 8 bytes).

``~= Math.pow(2, 1024) - 1``

### 2.4 Number.MIN_SAFE_INTEGER

The minimum safe value (including the sign symbol).

``-(Math.pow(2, 53) - 1)``

### 2.5 Number.MIN_VALUE

The minimum value (absolute value) that js can represent.

``Math.pow(2, -1074)``

### 2.6 Number.NEGATIVE_INFINITY

Negative infinity.

``-Infinity``

### 2.7 Number.POSITIVE_INFINITY

Positive infinity.

``+Infinity``

### 2.8 Number.NaN

It's non-numeric.

## 3. The Cause Of The strange Phenomenon

### 3.1 Why the result of 0.1 + 0.2 is 0.30000000000000004

It's similar to the approximation algorithm for `0.3`.

``````Storage for 0.1：[2]0.00011001100110011001100110011001100110011001100110011010

(f = 1001100110011001100110011001100110011001100110011010, e = 1019)

Storage for 0.2：[2]0.0011001100110011001100110011001100110011001100110011010

(f = 1001100110011001100110011001100110011001100110011010, e = 1020)
0.1 + 0.2: 0.0100110011001100110011001100110011001100110011001100111

(f = 00110011001100110011001100110011001100110011001100111, e = 1021)``````

However, there are 53 bits for `f = 00110011001100110011001100110011001100110011001100111`, which exceeds the normal 52 bits and cannot be stored, so it takes the nearest number:

``````0.1 + 0.2: 0.010011001100110011001100110011001100110011001100110100

(f = 0011001100110011001100110011001100110011001100110100, e = 1021)``````

Thus Js reads this number as 0.30000000000000004

### 3.2 Why the result of Math.pow(2, 53) + 1 is Math.pow(2, 53)

`Math.pow(2, 53) + 1` cannot be formulated and cannot be stored in memory, so it has to take the number that can be formulated and is closest.

The closest and smaller number:

``````Math.pow(2, 53)

(f = 0000000000000000000000000000000000000000000000000000, e = 1076)``````

The closest and bigger number:

``````Math.pow(2, 53) + 2

(f = 0000000000000000000000000000000000000000000000000001, e = 1076)``````

Take the first number: `Math.pow(2, 53)`.

So:

``````> Math.pow(2, 53) + 1 === Math.pow(2, 53)
true``````

temp