Понимание памяти JS и хранилища переменных

внешний интерфейс JavaScript
Понимание памяти JS и хранилища переменных

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

Волшебное число JS

Случай 1: расчет и перевод суммы

18.9 * 100
=1889.9999999999998

Случай 2: нарушение математических законов

0.1 + 0.2 === 0.3
// false

(function (a, b, c) {
    return a + b + c === a + ( b + c )
})(0.1, 0.2, 0.3)
// false

Случай 3: сложение в бесконечном цикле

(function (num) {
    while(true) {
        if (++num % 13 === 0) {
            return num
        }
    }
})(2 ** 53)

Случай 4: JSON.parse

JSON.parse('{"a":180143985094813214124}')
//{a: 180143985094813220000}

Из приведенных выше четырех случаев мы можем видеть, что операции с числами в компьютерах часто преподносят людям некоторые «сюрпризы».Чтобы предотвратить эти неожиданные результаты, мы должны сначала понятьКак число хранится в Javascript?

хранить номера

Компьютеры хранят данные в двоичном формате, поэтому числа также необходимо преобразовать в соответствующий двоичный код:00или11Различные комбинации последовательностей.

Как преобразовать двоичный файл

Как преобразовать число в двоичное, вот пример для иллюстрации:

поставить десятичную106.6953125106.6953125преобразовать в двоичный

При столкновении с десятичным преобразованием целая и десятичная части должны обрабатываться отдельно.106106Поделить на22пока частное00до сих пор брать каждое подразделение22получить оставшийся результат

106 / 2 = 53  ...... 0
53  / 2 = 26  ...... 1
26  / 2 = 13  ...... 0
13  / 2 = 6   ...... 1
6   / 2 = 3   ...... 0
3   / 2 = 1   ...... 1
1   / 2 = 0   ...... 1
结果为得到的余数按照从右往左排列   1101010

десятичная дробь0.69531250.6953125умножить на22до тех пор, пока не останется десятичных разрядов, и посчитайте целочисленный результат после каждого умножения,

0.6953125 x 2 = 1.390625  ...... 1
0.390625  x 2 = 0.78125   ...... 0
0.78125   x 2 = 1.5625    ...... 1
0.5625    x 2 = 1.125     ...... 1
0.125     x 2 = 0.25      ...... 0
0.25      x 2 = 0.5       ...... 0
0.5       x 2 = 1         ...... 1
结果为得到的整数位按照从左往右排列   1011001

будет рассчитан00 11Последовательности объединяются, чтобы получить преобразованный двоичный файл1101010.10110011101010.1011001, выраженный в научной записи как1.1010101011001*261.1010101011001*2^6, вычисляется двоичное число, а затем его необходимо сохранить в компьютере.В Javascript нет различия между целыми и десятичными числами.Числа равномерно хранятся в соответствии с требованиями чисел с плавающей запятой двойной точности, в основном включая следующие правила:

  • использовать8bytes(64bits)8bytes(64bits)Сохраняет числа с плавающей запятой двойной точности
  • Сохраняет данные с десятичными знаками в экспоненциальном представлении.
  • Первая цифра указывает на символ после1111Биты представляют экспоненту,Показатель действует согласно дополнению, то есть непосредственно10231023Дополнительная цифра
  • остальной5252биты представляют мантиссу после запятой,Превосходить5252часть бита00Покидать11Войти

Поскольку 11 бит бита степени не включают бит знака, для достижения эффекта положительных и отрицательных степеней введениесмещение экспоненты.

На схеме это представлено следующим образом:

Screen Shot 2021-08-17 at 12.20.14 PM.png

Помещаем преобразованные двоичные числа в память по правилам, сначала106.6953125106.6953125является положительным числом, поэтому бит знака должен быть00,00представляет положительный знак,11Указывает отрицательный знак

Screen Shot 2021-08-17 at 12.20.22 PM.png

бинарный1.1010101011001*261.1010101011001*2^6индекс66(Здесь необходимо добавить смещение 1023), преобразованное в двоичное как1000000010110000000101, бит экспоненты требует размещения дополнения до двух, и правило вычисления для дополнения:

  • Дополнением положительного числа является само
  • Дополнение отрицательного числа основано на исходном коде, знаковый бит остается неизменным, остальные биты инвертируются, и, наконец, +1 (то есть +1 на основе дополнения).
[+1] = [00000001]原 = [00000001]反

[-1] = [10000001]原 = [11111110]反

Таким образом, бит индекса изображения должен быть заполнен

Screen Shot 2021-08-17 at 12.20.47 PM.png

Часть мантиссы может непосредственно заполнять двоичный код, преобразованный из десятичного

Screen Shot 2021-08-17 at 12.21.37 PM.png

В итоге числа сохраняются в компьютере в таком виде

why 0.1 + 0.2 !== 0.3?

Поняв принцип цифрового хранения, давайте проанализируем, почему0.1+0.2!==0.30.1 + 0.2 !== 0.3

Первое место0.10.1 0.20.2 0.30.3преобразовать в двоичный

0.1 x 2 = 0.2  ...... 0
0.2 x 2 = 0.4  ...... 0
0.4 x 2 = 0.8  ...... 0
0.8 x 2 = 1.6  ...... 1
0.6 x 2 = 1.2  ...... 1
0.2 x 2 = 0.4  ...... 0
0.4 x 2 = 0.8  ...... 0
0.8 x 2 = 1.6  ...... 1
0.6 x 2 = 1.2  ...... 1
得到的整数位按照从左往右排列   000110011...

0.10.00011(0011)0.1 \rightarrow 0.00011(0011)_\infty

0.2 x 2 = 0.4  ...... 0
0.4 x 2 = 0.8  ...... 0
0.8 x 2 = 1.6  ...... 1
0.6 x 2 = 1.2  ...... 1
0.2 x 2 = 0.4  ...... 0
0.4 x 2 = 0.8  ...... 0
0.8 x 2 = 1.6  ...... 1
0.6 x 2 = 1.2  ...... 1
0.2 x 2 = 0.4  ...... 0
得到的整数位按照从左往右排列   001100110...

0.20.00110(0110)0.2 \rightarrow 0.00110(0110)_\infty

0.3 x 2 = 0.6  ...... 0
0.6 x 2 = 1.2  ...... 1
0.2 x 2 = 0.4  ...... 0
0.4 x 2 = 0.8  ...... 0
0.8 x 2 = 1.6  ...... 1
0.6 x 2 = 1.2  ...... 1
0.2 x 2 = 0.4  ...... 0
0.4 x 2 = 0.8  ...... 0
0.8 x 2 = 1.6  ...... 1
得到的整数位按照从左往右排列   010011001...

0.30.01001(1001)0.3 \rightarrow 0.01001(1001)_\infty

унифицирован в научной нотации как

0.10.00011(0011)1.(1001)*240.1 \rightarrow 0.00011(0011)_\infty \rightarrow 1.(1001)_\infty*2^{-4}

0.20.00110(0110)1.(1001)*230.2 \rightarrow 0.00110(0110)_\infty \rightarrow 1.(1001)_\infty*2^{-3}

0.30.01001(1001)1.(0011)*220.3 \rightarrow 0.01001(1001)_\infty \rightarrow 1.(0011)_\infty*2^{-2}

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

Screen Shot 2021-08-17 at 12.30.01 PM.png

Screen Shot 2021-08-17 at 12.30.27 PM.png

Screen Shot 2021-08-17 at 12.32.27 PM.png

Затем после 64-битного хранения с двойной точностью двоичный файл представляется следующим образом

0.1001111111011(1001)1210100.1 \rightarrow 0-01111111011-(1001)_{12}1010

0.2001111111100(1001)1210100.2 \rightarrow 0-01111111100-(1001)_{12}1010

0.3001111111101(0011)1200110.3 \rightarrow 0-01111111101-(0011)_{12}0011

В настоящее время0.1+0.20.1 + 0.2можно увидеть с0.30.3не равный

8.png

Вот так операции с числами в компьютере часто преподносят людям какие-то «сюрпризы»!

заключительные замечания

Если эта статья была вам полезна, ставьте лайк 😯

Если в тексте есть ошибки, исправьте их, если есть дополнения, оставьте сообщение.