Статьи

Как отображать числа в JavaScript


Этот пост в блоге объясняет, как JavaScript отображает числа.
Он также проверяет, когда JavaScript использует экспоненциальную запись и когда он использует фиксированную запись.

Этот пост является частью серии о числах JavaScript, которая в настоящее время включает в себя следующий пост:

Отображение десятичных чисел

Числа JavaScript внутренне хранятся в двоичной с плавающей точкой. Но они обычно отображаются в десятичной системе.

Фиксированная запись против экспоненциальной записи

В JavaScript используются две десятичные записи: Фиксированная запись


[«+» |
«-«] цифра + [«.» цифра +]

и экспоненциальная запись


[«+» |
«-«] цифра [«.» цифра +] «е» [«+» | «-«] цифра +

Пример экспоненциального обозначения -1,37e + 2. Для вывода перед точкой всегда стоит ровно одна цифра, для ввода можно использовать более одной цифры. Экспоненциальная запись интерпретируется следующим образом: задано число в экспоненциальной записи

    significand e exponent

Значение этого числа


значение и × 10
показатель

Следовательно, -1.37e + 2 представляет число -137.

Отображение десятичных чисел

Правила отображения чисел можно обобщить следующим образом:

  • Используйте экспоненциальную запись, если перед десятичной запятой находится больше 21 цифры. Пример:

    > 1234567890123456789012
        1.2345678901234568e+21
        > 123456789012345678901
        123456789012345680000
  • Use exponential notation if number starts with “0.” followed by more than five zeros. Example:

        > 0.0000003
        3e-7
        > 0.000003
        0.000003
  • Otherwise, use fixed notation.

Read on if you want to know more about how displaying numbers is specified.

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 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

The general idea is that you only need integers if you store a floating point number as a pair (mantissa, exponent), to be interpreted like this:

mantissa × 10
exponent

The ECMAScript specification varies this idea by expressing a number as

mantissa × 10
pointPos−digitCount

Hence, 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 = 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
  •  

The algorithm

Given a number

mantissa × 10
pointPos−digitCount

The algorithm has four main cases (here, the last case merges the actual algorithm’s last two cases).

  1. No decimal point: digitCount ≤ pointPos ≤ 21
    Print the digits (without leading zeros), followed by pointPos−digitCount zeros.

  2. 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.

  3. Decimal point comes before the mantissa: −6 < pointPos ≤ 0
    Display a 0 followed by a point, −pointPos zeros and the mantissa.

  4. 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.

  5. mantissa
    0 [ «.» mantissa
    1..digitCount ]

         «e» signChar(pointPos−1) abs(pointPos−1)

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).

    > 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 allows you to convert such notations back to a number:

    > parseInt('kf12oi', 36)
    1234567890

If the radix is 10, the algorithm from Sect. 1 is used to convert the number to a string.

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.

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'

Получить экспоненциальную запись, когда ненулевые числа не достаточно малы.

    > 0.003.toString()
    '0.003'

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

    > 0.003.toExponential()
    '3e-3'

Number.prototype.toFixed (fractionDigits?)

Если число больше 10
21, то этот метод такой же, как toString (). Таким образом, вы не гарантированно не получите число в экспоненциальной записи.

    > 1234567890123456789012..toFixed()
    '1.2345678901234568e+21'

    > 1234567890123456789012..toString()
    '1.2345678901234568e+21'

В противном случае вы получите представление числа с фиксированной запятой, округленное до дробных цифр. Если параметр опущен, используется значение 0.

    > 0.0000003.toFixed(10)
    '0.0000003000'

    > 0.0000003.toString()
    '3e-7'

Number.prototype.toPrecision (точность?)

Этот метод сокращает мантиссу до точных цифр перед использованием алгоритма преобразования, подобного toString (). Если точность не указана, toString () используется напрямую.

    > 1234..toPrecision(3)
    '1.23e+3'
    
    > 1234..toPrecision(4)
    '1234'

    > 1234..toPrecision(5)
    '1234.0'
    
    > 1.234.toPrecision(3)
    '1.23'

Очевидно, что вам нужно экспоненциальное обозначение для отображения 1234 с точностью до 3 цифр.

Вывод

В этом посте описывается, как отображаются цифры JavaScript. Хотя их внутреннее представление является двоичным, по умолчанию для их отображения используется десятичное число. Результирующая потеря точности проблематична и станет темой следующего сообщения в блоге. Вы также узнали, что JavaScript использует фиксированные обозначения, за исключением чисел больше 10
21 и чисел, начинающихся с «0». следуют более 5 нулей.

Интересно отметить, что вы всегда можете добавить e x к числу, и оно будет умножено на 10 x .

    > 123e3
    123000
    > 123e-3
    0.123