Представление чисел в ЭВМ: прямой, обратный и дополнительный коды, формат с фиксированной точкой
Представление чисел в ЭВМ: прямой, обратный и дополнительный коды, формат с фиксированной точкой
Для человека число — это абстрактное понятие. Для компьютера — это набор электрических сигналов, интерпретируемых как нули и единицы. Главный вызов инженерной мысли заключался не в том, как сохранить число, а в том, как эффективно выполнять арифметические операции, особенно с отрицательными и дробными числами.
Мы разберем эволюцию представления целых чисел (от прямого кода к дополнительному) и принцип работы чисел с фиксированной точкой, который широко применяется в цифровой обработке сигналов и встроенных системах.
Бит, байт и проблема знака
В основе хранения данных лежит бит — ячейка, принимающая значение 0 или 1. Группы битов образуют байты (8 бит) и машинные слова (16, 32, 64 бита).
Положительные целые числа хранятся как обычный перевод из десятичной системы в двоичную. Например, число 5 в одном байте:
Где индекс указывает на двоичную систему счисления.
Для записи отрицательных чисел инженеры выделили самый старший (левый) бит под знак числа:
- 0 в старшем бите — число положительное.
- 1 в старшем бите — число отрицательное.
Этот принцип используется во всех методах кодирования целых чисел.
Прямой код (Sign-Magnitude)
Это наиболее интуитивный способ. Мы берем двоичную запись модуля числа и устанавливаем знаковый бит.
Рассмотрим 8-битные числа:
- в прямом коде: 00000101
- в прямом коде: 10000101
Формально представление описывается так:
Где — представление числа в прямом коде, а — абсолютное значение (модуль) числа .
Недостатки прямого кода
Несмотря на простоту, прямой код имеет два критических недостатка:
- Два нуля. Существует «положительный ноль» (00000000) и «отрицательный ноль» (10000000). Это усложняет схемотехнику процессора, так как требуется дополнительная проверка при сравнении чисел.
- Сложная арифметика. Сложение чисел с разными знаками нельзя выполнить простым суммированием битов. Процессору нужно сравнивать модули, определять знак результата и выполнять вычитание.
Обратный код (Ones' Complement)
Обратный код был попыткой упростить арифметику. Правило формирования:
- Положительные числа: совпадают с прямым кодом.
- Отрицательные числа: получаются путем инверсии всех битов положительного числа (0 меняется на 1, 1 на 0).
Пример для числа :
- Берем :
00000101 - Инвертируем все биты:
11111010
Результат 11111010 — это в обратном коде.
Проблемы обратного кода
Хотя вычитание стало проще (его можно свести к сложению), проблема двух нулей осталась:
- :
00000000 - :
11111111(инверсия всех нулей)
Из-за этого недостатка обратный код в современных универсальных процессорах практически не используется.
Дополнительный код (Two's Complement)
Это стандарт де-факто в современной вычислительной технике. Дополнительный код решает проблему двух нулей и позволяет выполнять вычитание через сложение без дополнительных корректировок.
Алгоритм получения
Для положительных чисел код совпадает с прямым. Для отрицательных:
- Записать модуль числа в двоичном виде.
- Инвертировать все биты (получить обратный код).
- Прибавить 1 к младшему разряду.
Пример для числа :
- :
00000101 - Инверсия:
11111010 - Прибавляем 1:
11111010+1=11111011
Результат: 11111011 — это в дополнительном коде.
Математически это выражается формулой для -битного числа:
Где — представление отрицательного числа в дополнительном коде, — разрядность (количество бит), — модуль числа.
Преимущества дополнительного кода
- Единственный ноль. Ноль всегда записывается как
00000000. Инверсия нулей (11111111) плюс единица дает1 00000000, где единичка переполнения отбрасывается, оставляя чистые нули. - Универсальная арифметика. Процессору не нужно знать, вычитает он или складывает. Он просто складывает биты. Например, :
Результат 11111101 — это действительно в дополнительном коде (инверсия даст 00000010, плюс 1 = 00000011, то есть 3).
Числа с фиксированной точкой (Fixed Point)
До сих пор мы говорили о целых числах. Но как представить дробь, например, или ? Существует два подхода: плавающая точка (Floating Point, стандарт IEEE 754) и фиксированная точка.
Фиксированная точка — это способ представления дробных чисел, при котором позиция разделителя целой и дробной части жестко зафиксирована.
По сути, компьютер хранит обычное целое число, но программист «договаривается» с машиной, что реальное значение умножено на некий масштабный коэффициент.
Формат Q (Q-notation)
Часто используется запись вида Qn.m, где:
- — количество бит для целой части (иногда включая знак).
- — количество бит для дробной части.
Рассмотрим 8-битное число в формате Q4.4 (4 бита целых, 4 бита дробных).
Пусть в памяти записано число: 00101100.
Мы мысленно ставим точку посередине: 0010.1100.
Расчет значения
Значение числа рассчитывается как сумма степеней двойки, где дробные разряды имеют отрицательные степени:
Где — итоговое значение, — количество дробных бит, — количество целых бит, — значение бита (0 или 1) в позиции , — вес разряда.
Разберем пример 0010.1100:
- Целая часть
0010: - Дробная часть
1100:
Посчитаем дробную часть:
Итоговое число: .
Альтернативный взгляд: Масштабирование
Можно смотреть на это проще: мы храним целое число , а реальное значение получаем делением на (где — количество дробных бит).
В нашем примере 00101100 как простое целое равно .
Поскольку у нас 4 дробных бита, делим на :
Где — реальное число, — целочисленное представление в памяти, — масштабный коэффициент.
Плюсы и минусы фиксированной точки
Преимущества:
- Скорость: Операции сложения и вычитания выполняются так же быстро, как с обычными целыми числами. Не нужен сопроцессор плавающей точки (FPU).
- Точность: Абсолютная погрешность постоянна по всему диапазону чисел.
Недостатки:
- Ограниченный диапазон: Мы не можем записывать очень большие и очень маленькие числа одновременно (в отличие от плавающей точки).
- Сложность умножения: При перемножении двух чисел формата Q4.4 результат будет иметь формат Q8.8, и его нужно приводить обратно к Q4.4, теряя точность.
Фиксированная точка — основной инструмент в микроконтроллерах, финансовом ПО (где важна точность до копейки и недопустимы ошибки округления плавающей точки) и графике реального времени.