Как работает компьютер

Компьютер — машина, которая принимает данные (input), обрабатывает их по инструкциям (process), и выдаёт результат (output), используя двоичную систему.

Зачем нужно

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

Где используется

  • Оптимизация производительности приложений
  • Понимание ограничений (память, CPU)
  • Отладка низкоуровневых проблем
  • Проектирование систем и выбор архитектуры

Предпосылки

  • Базовая математика (степени двойки)
  • Понимание единиц измерения (бит, байт, КБ, МБ, ГБ)

Двоичная система (Binary)

Компьютер работает с электрическими сигналами: есть напряжение (1) или нет (0). Вся информация — числа, текст, изображения, звук — кодируется комбинациями нулей и единиц.

Биты и байты

1 бит (bit)   = 0 или 1
1 байт (byte) = 8 бит = 256 возможных значений (0–255)
1 КБ          = 1024 байт
1 МБ          = 1024 КБ
1 ГБ          = 1024 МБ

Перевод из десятичной в двоичную

Десятичное 13 → Двоичное:
13 ÷ 2 = 6 остаток 1
 6 ÷ 2 = 3 остаток 0
 3 ÷ 2 = 1 остаток 1
 1 ÷ 2 = 0 остаток 1
Читаем снизу вверх: 1101
// JavaScript и двоичная система
const decimal = 13;
const binary = decimal.toString(2);   // "1101"
const back = parseInt("1101", 2);     // 13

// Побитовые операции
console.log(5 & 3);   // 1  (AND: 101 & 011 = 001)
console.log(5 | 3);   // 7  (OR:  101 | 011 = 111)
console.log(5 ^ 3);   // 6  (XOR: 101 ^ 011 = 110)
console.log(~5);       // -6 (NOT: инвертирует все биты)
console.log(5 << 1);   // 10 (сдвиг влево = умножение на 2)
console.log(5 >> 1);   // 2  (сдвиг вправо = деление на 2)

Представление данных

Тип данных Как хранится
Числа целые Двоичное дополнение (two's complement)
Числа дробные IEEE 754 (float64 в JS)
Текст UTF-8 / UTF-16 (код символа → байты)
Цвет RGB: 3 байта (красный, зелёный, синий)
Звук Амплитуда волны → числа (PCM)
// Почему 0.1 + 0.2 !== 0.3
console.log(0.1 + 0.2);          // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3);  // false

// IEEE 754: 0.1 в двоичной системе — бесконечная дробь
// 0.1₁₀ = 0.0001100110011... (повторяется бесконечно)
// При хранении в 64 битах дробь обрезается → погрешность

// Решение: сравнивать с допуском (epsilon)
function almostEqual(a, b) {
  return Math.abs(a - b) < Number.EPSILON;
}
console.log(almostEqual(0.1 + 0.2, 0.3)); // true

Архитектура компьютера (модель фон Неймана)

┌──────────────────────────────────────────────┐
│                    CPU                        │
│  ┌───────────┐  ┌───────────────────────┐    │
│  │  ALU      │  │  Control Unit (CU)    │    │
│  │ Арифметика│  │  Управление           │    │
│  │ и логика  │  │  потоком команд       │    │
│  └───────────┘  └───────────────────────┘    │
│  ┌───────────────────────────────────────┐   │
│  │  Регистры (сверхбыстрая память)       │   │
│  └───────────────────────────────────────┘   │
└────────────────────┬─────────────────────────┘
                     │ Шина (Bus)
┌────────────────────┴─────────────────────────┐
│              RAM (оперативная память)          │
│  Быстрая, но энергозависимая                  │
│  Хранит запущенные программы и данные         │
└────────────────────┬─────────────────────────┘
                     │
┌────────────────────┴─────────────────────────┐
│         Накопитель (SSD / HDD)                │
│  Медленная, но постоянная память              │
│  Файлы, ОС, программы                        │
└──────────────────────────────────────────────┘

Компоненты

CPU (Central Processing Unit)

Процессор выполняет инструкции в цикле:

1. Fetch   — загрузить инструкцию из памяти
2. Decode  — расшифровать, что делать
3. Execute — выполнить операцию
4. Store   — сохранить результат
→ Повторить

Тактовая частота (GHz) — сколько циклов в секунду. 3 GHz = ~3 миллиарда циклов/с.

RAM (Random Access Memory)

Оперативная память — быстрый доступ к любой ячейке по адресу. Данные теряются при выключении.

// Когда вы создаёте переменную — она попадает в RAM
let x = 42;       // 8 байт в RAM (Number = float64)
let s = "hello";  // ~10 байт + служебные данные
let arr = [1, 2]; // объект массива + элементы

// При перезагрузке страницы — всё из RAM стирается

Иерархия памяти

Скорость      Объём      Тип
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
~0.5 нс       КБ         Регистры CPU
~1-2 нс       КБ–МБ      L1 Cache
~3-10 нс      МБ         L2 / L3 Cache
~50-100 нс    ГБ         RAM (DDR)
~0.1 мс       ТБ         SSD
~5-10 мс      ТБ         HDD
~50-150 мс    ∞          Сеть (HTTP запрос)

Каждый следующий уровень в 10-1000 раз медленнее, но в 10-1000 раз больше.

Накопители (Storage)

Параметр HDD SSD NVMe SSD
Скорость чтения ~100 МБ/с ~500 МБ/с ~3500 МБ/с
Случайный доступ ~5-10 мс ~0.1 мс ~0.02 мс
Механические части Да Нет Нет
Надёжность Средняя Высокая Высокая

Как программа выполняется

1. Программа хранится на диске (файл .js, .exe)
2. ОС загружает программу в RAM
3. CPU читает инструкции из RAM
4. CPU выполняет инструкции (ALU для вычислений)
5. Результаты записываются обратно в RAM
6. При необходимости — вывод на экран, диск, сеть
// Что происходит, когда Node.js выполняет скрипт:
// 1. Файл читается с диска → в RAM
// 2. V8 парсит текст → создаёт AST (в RAM)
// 3. AST → байткод (в RAM)
// 4. CPU выполняет байткод
// 5. Горячие функции → машинный код (JIT, в RAM)

function fibonacci(n) {
  // Каждый вызов создаёт стековый фрейм в RAM
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
  // Рекурсия = много фреймов = много RAM
}

console.log(fibonacci(10)); // 55
// ~177 вызовов функции = ~177 стековых фреймов

Частые ошибки

  1. Думать, что RAM и диск — одно и то же. RAM — временная, быстрая; диск — постоянный, медленный
  2. Игнорировать погрешность float. 0.1 + 0.2 !== 0.3 — это не баг JavaScript, это IEEE 754
  3. Не учитывать объём памяти. Массив из миллиона объектов может занять сотни МБ
  4. Путать частоту CPU с производительностью. Архитектура, кэш, количество ядер важны не менее частоты

Практика

  1. Откройте диспетчер задач и посмотрите, сколько RAM использует браузер
  2. Реализуйте функцию перевода числа в двоичную систему без toString(2):
    function toBinary(num) {
      if (num === 0) return "0";
      let result = "";
      while (num > 0) {
        result = (num % 2) + result;
        num = Math.floor(num / 2);
      }
      return result;
    }
    console.log(toBinary(13)); // "1101"
    
  3. Проверьте: Number.MAX_SAFE_INTEGER — максимальное целое число без потери точности

Связанные темы

Ресурсы

  • Crash Course Computer Science (YouTube) — визуальный курс
  • Code: The Hidden Language of Computer Hardware and Software (Charles Petzold)
  • nand2tetris.org — соберите компьютер с нуля
  • learn.javascript.ru — раздел про типы данных