Прямой, обратный и дополнительный код
Как целочисленные числа хранятся в памяти компьютера — и чем отличаются три схемы двоичного кодирования.
1. Как байт выглядит в памяти
Числа в памяти компьютера хранятся в двоичном виде. Тип byte в Java занимает 8 бит. Каждый бит хранит 0 или 1:
В знаковых целых числах старший (самый левый) бит является знаковым битом: 0 — положительное, 1 — отрицательное. Оставшиеся 7 бит кодируют величину числа. Это основа для всех трёх схем кодирования.
2. Прямой код (sign-magnitude)
Наиболее интуитивная кодировка. Знаковый бит указывает направление, а оставшиеся 7 бит хранят точное двоичное значение величины числа.
| Десятичное | Прямой код (8 бит) |
|---|---|
| 3 | 0 000 0011 |
| 2 | 0 000 0010 |
| 1 | 0 000 0001 |
| 0 | 0 000 0000 |
| −0 | 1 000 0000 |
| −1 | 1 000 0001 |
| −2 | 1 000 0010 |
0 000 0000 (+0) и 1 000 0000 (−0). Арифметические схемы вынуждены обрабатывать это как особый случай, что усложняет аппаратную реализацию. Современные процессоры используют дополнительный код.3. Обратный код (one's complement)
Для получения обратного кода инвертируются все биты числа — включая знаковый бит. Ни один бит не является исключением.
В обратном коде сохраняется проблема двух нулей. Значение 1 111 1111 представляет −0, что отличается от +0 (0 000 0000). Дополнительный код решает эту проблему.
4. Дополнительный код (two's complement)
Именно так Java (и практически все современные процессоры) хранят отрицательные целые числа. Дополнительный код устраняет проблему двойного нуля и позволяет выполнять сложение и вычитание одной аппаратной операцией независимо от знака.
Алгоритм перевода положительного числа в дополнительный код
Инвертируются все биты — включая знаковый бит (это даёт обратный код):
К результату прибавляется единица:
1111 1100. Проверим: 1111 1100 + 0000 0100 = 0000 0000 (переполнение отбрасывается) ✓5. Сводная таблица
| Десятичное | Прямой код | Обратный код | Дополнительный код |
|---|---|---|---|
| 0 | 0 000 0000 | 0 000 0000 | 0 000 0000 |
| −0 | 1 000 0000 | 1 111 1111 | — (нет −0) |
| −1 | 1 000 0001 | 1 111 1110 | 1 111 1111 |
| −2 | 1 000 0010 | 1 111 1101 | 1 111 1110 |
| −3 | 1 000 0011 | 1 111 1100 | 1 111 1101 |
| −4 | 1 000 0100 | 1 111 1011 | 1 111 1100 |
| −5 | 1 000 0101 | 1 111 1010 | 1 111 1011 |
6. Диапазоны целочисленных типов в Java
Все четыре целочисленных примитива Java используют дополнительный код. Асимметрия диапазона (одно дополнительное отрицательное значение) — прямое следствие устранения −0.
Часто задаваемые вопросы
Почему диапазон byte — от −128 до +127, а не симметричный?
Потому что Java хранит числа в дополнительном коде, где у нуля только одно представление. В прямом и обратном коде ноль занимает две битовые комбинации (+0 и −0), а в дополнительном — одну. Освободившаяся комбинация отдаётся под дополнительное отрицательное значение. Поэтому 8-битное знаковое целое охватывает от −128 до +127: отрицательных значений на одно больше, чем положительных.
Зачем нужен дополнительный код, если есть прямой?
Дополнительный код решает две проблемы прямого. Во-первых, у нуля становится единственное представление (нет отдельных +0 и −0). Во-вторых, сложение и вычитание чисел любого знака выполняются одной и той же аппаратной операцией — процессору не нужно отдельно обрабатывать знак. Это упрощает и ускоряет вычисления, поэтому дополнительный код используют практически все современные процессоры и Java.
Чем обратный код отличается от дополнительного?
Обратный код получается инвертированием всех битов числа. Дополнительный код — это обратный код плюс единица. Ключевое отличие в результате: обратный код по-прежнему имеет два представления нуля (проблема −0 остаётся), а дополнительный — только одно. Именно поэтому современные системы используют дополнительный, а не обратный код.
Что такое знаковый бит?
Знаковый бит — это старший (самый левый) бит в знаковом целом числе. Он указывает знак: 0 — число положительное, 1 — отрицательное. Остальные биты кодируют величину числа. Например, в 8-битном byte под знак отводится 1 бит, а под величину — оставшиеся 7 бит. Знаковый бит — основа всех трёх схем кодирования: прямого, обратного и дополнительного кода.
Видео объяснение
Предпочитаете видеоформат? Посмотрите этот урок с примерами и объяснениями.
Комментарии