[2012-03-12] numbers, dev, javascript, jslang

(Ad, please don’t block)

This blog post explains how JavaScript displays numbers. It also examines when JavaScript uses exponential notation and when it uses fixed notation.
## Displaying decimal numbers

JavaScript numbers are internally stored in binary floating point. But they are usually displayed in the decimal system.
### Fixed notation versus exponential notation

There are two decimal notations used by JavaScript: Fixed notation
`-1.37e+2`. For output, there is always exactly one digit before the point, for input you can use more than one digit. Exponential notation is interpreted as follows: Given a number in exponential notation
`-1.37e+2` represents the number −137.
### Displaying decimal numbers

The rules for displaying numbers are can be summarized as follows:
## The ECMAScript 5.1 display algorithm in detail

Sect. 9.8.1 of the ECMAScript 5.1 specification describes the algorithm for displaying a decimal number. This section explains it. We first need to make a few preliminary definitions.
### Preliminary definitions

The *mantissa* of a floating point number is an integer – the significant digits plus a sign. Leading and trailing zeros are discarded. Examples:
### The algorithm

Given a number
## Methods for converting numbers to string

This conversion is usually a preliminary step for displaying a number: Convert the number to a string that “looks” as desired and then show it somewhere.
### Number.prototype.toString(radix?)

The parameter `radix` indicates the base of the system in which the number is to be displayed. The most common radices are 10 (decimal), 2 (binary) and 16 (hexadecimal).
`parseInt` allows you to convert such notations back to a number:
### Number.prototype.toExponential(fractionDigits?)

This method forces a number to be expressed in exponential notation. `fractionDigits` is a number between 0 and 20 that determines how many digits should be shown after the decimal point. If it is omitted then “include as many significand [mantissa] digits as necessary to uniquely specify the Number” (ECMAScript 5.1 specification, Sect. 15.7.4.6). The following are a few examples.
### Number.prototype.toFixed(fractionDigits?)

If the number is greater than 10^{21} then this method is the same as `toString()`. Thus, you are not guaranteed to not get a number in exponential notation.
`fractionDigits` digits. If the parameter is omitted, the value 0 is used.
### Number.prototype.toPrecision(precision?)

This method prunes the mantissa to `precision` digits, before using a conversion algorithm similar to `toString()`. If no `precision` is given, `toString()` is used directly.
## Conclusion

This post described how JavaScript numbers are displayed. While their internal representation is binary, the default for displaying them is decimal. The resulting loss in precision is problematic and will be the topic of an upcoming blog post. You have also learned that JavaScript uses fixed notation except for numbers greater than 10^{21} and numbers that start with “0.” followed by more than 5 zeros.

This post is part of a series on JavaScript numbers that currently comprises the following other post:

[ "+" | "-" ] digit+ [ "." digit+ ]and exponential notation

[ "+" | "-" ] digit [ "." digit+ ] "e" [ "+" | "-" ] digit+An example of exponential notation is

The value of that number issignificandeexponent

significand × 10Hence,^{exponent}

- Use exponential notation if there are more than 21 digits before the decimal point. Example:
> 1234567890123456789012 1.2345678901234568e+21 > 123456789012345678901 123456789012345680000

- Use exponential notation if the number starts with “0.” followed by more than five zeros. Example:
> 0.0000003 3e-7 > 0.000003 0.000003

- Otherwise, use fixed notation.

- The mantissa of 12.34 is 1234.
- The mantissa of 0.00045 is 45
- The mantissa of 1000 is 1
- The mantissa of −27 is −27

mantissa × 10The ECMAScript specification varies this idea by expressing a number as^{exponent}

mantissa × 10Hence, the previous exponent is now pointPos−digitCount. digitCount denotes the “length” of the mantissa, the number of digits that it has. Based on that definition, pointPos works as follows.^{pointPos−digitCount}

- pointPos = 0: point is before the digits.
> 123 * Math.pow(10, 0 - 3) 0.123

- pointPos ≥ 1: point is after the 1st (2nd, etc.) digit. If pointPos is less than digitCount then then the point appears “inside” the mantissa:
> 123 * Math.pow(10, 1 - 3) 1.23

If pointPos is the same as digitCount then the point appears after the last digit of the mantissa.> 123 * Math.pow(10, 3 - 3) 123

If pointPos is greater than digitCount then zeros are inserted after the mantissa and before the point.> 123 * Math.pow(10, 5 - 3) 12300

- pointPos ≤ −1: one (two, etc.) zeros appear after the point and before the mantissa.
> 123 * Math.pow(10, -2 - 3) 0.00123

mantissa × 10The algorithm has four main cases (the last case covers the actual algorithm’s last two cases).^{pointPos−digitCount}

**No decimal point:**digitCount ≤ pointPos ≤ 21

Print the digits (without leading zeros), followed by pointPos−digitCount zeros.**Decimal point inside the mantissa:**0 < pointPos ≤ 21, pointPos < digitCount

Display the pointPos first digits of the mantissa, a point and then the remaining digitCount−pointPos digits.**Decimal point comes before the mantissa:**−6 < pointPos ≤ 0

Display a 0 followed by a point, −pointPos zeros and the mantissa.**Exponential notation:**pointPos ≤ -6 or pointPos > 21

Display the first digit of the mantissa. If there are more digits then display a point and the remaining digits. Next, display the character`e`and a plus or minus sign (depending on the sign of pointPos−1), followed by the absolute value of pointPos−1. Therefore, the result looks as follows.mantissa

_{0}[ "." mantissa_{1..digitCount}]

"e" signChar(pointPos−1) abs(pointPos−1)

> 15..toString(2) '1111' > 65535..toString(16) 'ffff'The radix must be at least 2 and at most 36. Any radix greater than 10 leads to alphabetical characters being used as digits, which explains the maximum 36, as the latin alphabet has 26 characters.

> 1234567890..toString(36) 'kf12oi'The global function

> parseInt('kf12oi', 36) 1234567890If the radix is 10, the algorithm from Sect. 1 is used to convert the number to a string.

Force more precision when `toString()` would also use exponential notation. Results are mixed, because one reaches the limits of the precision that can be achieved when converting binary numbers to a decimal notation.

> 1234567890123456789012..toString() '1.2345678901234568e+21' > 1234567890123456789012..toExponential(20) '1.23456789012345677414e+21'

Get exponential notation when numbers are not large enough.

> 1234..toString() '1234' > 1234..toExponential(5) '1.23400e+3' > 1234..toExponential() '1.234e+3'

Get exponential notation when non-zero numbers are not small enough.

> 0.003.toString() '0.003' > 0.003.toExponential(4) '3.0000e-3' > 0.003.toExponential() '3e-3'

> 1234567890123456789012..toFixed() '1.2345678901234568e+21' > 1234567890123456789012..toString() '1.2345678901234568e+21'Otherwise, you will get a fixed point representation of the number, rounded to

> 0.0000003.toFixed(10) '0.0000003000' > 0.0000003.toString() '3e-7'

> 1234..toPrecision(3) '1.23e+3' > 1234..toPrecision(4) '1234' > 1234..toPrecision(5) '1234.0' > 1.234.toPrecision(3) '1.23'Obviously, you need the exponential notation to display 1234 with a precision of 3 digits.

It is interesting to note that you can always append `e x` to a number and it will be multiplied by 10

> 123e3 123000 > 123e-3 0.123