Целые числа, дополнительный код отрицательных чисел, числа с плавающей точкой и формат IEEE 754
Форматы представления чисел в памяти
В памяти компьютера любое число хранится как последовательность бит фиксированной длины (разрядности), но способ интерпретации этих бит зависит от типа числа. Различают представление целых чисел без знака, целых чисел со знаком и вещественных (дробных) чисел — для каждого из этих типов используется свой формат кодирования.
Целые числа без знака
Целое число без знака хранится просто как его запись в двоичной системе счисления, дополненная нулями слева до нужной разрядности n. При разрядности n бит можно представить 2ⁿ различных неотрицательных чисел — от 0 до 2ⁿ−1 включительно. Например, при n=8 бит диапазон представимых чисел без знака — от 0 до 255 (2⁸−1).
Целые числа со знаком: прямой и обратный коды
Чтобы хранить и отрицательные числа, старший (самый левый) бит отводят под знак: 0 означает положительное число, 1 — отрицательное. В прямом коде положительного числа его абсолютная величина просто записывается в оставшихся n−1 битах; для отрицательного числа в прямом коде также записывается абсолютная величина, но со знаковым битом 1. Такой способ прост, но неудобен для арифметики: при сложении чисел разных знаков в прямом коде нельзя просто складывать биты столбиком. Промежуточный вариант — обратный (инверсный) код: для отрицательного числа все биты его прямого кода (кроме знакового) инвертируются (0 заменяется на 1 и наоборот).
Дополнительный код
На практике для хранения и обработки отрицательных целых чисел практически все современные компьютеры используют дополнительный код, который получают из обратного кода прибавлением единицы к младшему разряду. Главное преимущество дополнительного кода — вычитание чисел сводится к обычному сложению, что сильно упрощает устройство процессора: не нужен отдельный аппаратный узел для вычитания. Алгоритм получения дополнительного кода отрицательного числа −X при разрядности n бит:
1) записать модуль |X| в двоичной системе, дополнив нулями слева до n бит; 2) инвертировать все биты полученной записи (получить обратный код); 3) прибавить 1 к младшему разряду.
Пример 1. Запись отрицательного числа в дополнительном коде
Дано: запишите число −5 в дополнительном коде, используя 8 бит.
Решение. Модуль числа |5|=5=00000101₂ (дополнено нулями до 8 бит). Инвертируем все биты, получая обратный код: 11111010. Прибавляем 1 к младшему разряду:
Ответ: 11111011₂. Проверка: как беззнаковое число 11111011₂=251, а 256−251=5 — то есть при интерпретации со знаком эта запись действительно кодирует −5.
Пример 2. Вычитание через сложение в дополнительном коде
Дано: вычислите 5+(−3), используя 8-битный дополнительный код, и убедитесь, что операция сводится к обычному сложению.
Решение. Дополнительный код числа 5: 00000101. Дополнительный код числа −3: модуль |3|=00000011, обратный код 11111100, дополнительный код 11111101. Складываем оба кода столбиком как обычные двоичные числа:
Так как разрядность фиксирована (8 бит), девятый (самый левый) бит переноса за пределы разрядной сетки отбрасывается, и остаётся результат 00000010₂=2.
Ответ: 5+(−3)=2 — результат сложения в дополнительном коде совпал с ожидаемым результатом обычного вычитания 5−3=2, что и демонстрирует главное преимущество дополнительного кода.
Диапазон представимых целых чисел
При разрядности n бит и использовании дополнительного кода один бит уходит под знак, поэтому диапазон представимых целых чисел со знаком:
Например, при n=8 бит диапазон — от −128 до 127 (обратите внимание на асимметрию: отрицательных значений на одно больше, так как ноль занимает одну из неотрицательных комбинаций). При n=32 бит (стандартный тип int во многих языках программирования) диапазон — от −2 147 483 648 до 2 147 483 647.
Числа с плавающей точкой
Для хранения вещественных (дробных) чисел с широким диапазоном значений (от очень маленьких до очень больших) используется формат с плавающей точкой, аналогичный экспоненциальной записи числа в математике: число представляется в виде произведения мантиссы (значащих цифр) на основание системы счисления в некоторой степени — порядке (экспоненте). Такое представление позволяет одним и тем же количеством разрядов охватить огромный диапазон величин ценой некоторой потери точности для очень больших чисел.
Формат IEEE 754
Наиболее распространённый стандарт хранения чисел с плавающей точкой — IEEE 754. В формате одинарной точности (32 бита, тип float) разряды распределены так: 1 бит под знак числа (s), 8 бит под порядок (экспоненту) со смещением 127, и 23 бита под дробную часть мантиссы. Число хранится в нормализованном виде — мантисса всегда начинается с неявной единицы перед точкой, поэтому эта единица в памяти не хранится явно, а лишь подразумевается. Значение числа вычисляется по формуле:
Пример 3. Представление числа в формате IEEE 754
Дано: представьте число 5,5 в формате IEEE 754 одинарной точности (обзорно, по шагам).
Решение. Переведём 5,5 в двоичную систему: целая часть 5=101₂, дробная часть 0,5=0,1₂ (так как 0,5=2⁻¹), итого 5,5=101,1₂. Нормализуем запись, сдвинув точку так, чтобы перед ней осталась одна значащая единица: 101,1₂=1,011₂·2². Знак положительный, s=0. Порядок со смещением: 2+127=129=10000001₂. Мантисса — дробная часть после нормализованной единицы, дополненная нулями до 23 бит: 01100000000000000000000.
Ответ: 5,5 в формате IEEE 754 (32 бита) записывается как 0 10000001 01100000000000000000000 (знак — порядок — мантисса).
Программная иллюстрация
Рассмотрим программу на Python, которая вычисляет n-битный дополнительный код целого числа и получает битовое представление вещественного числа в формате IEEE 754 одинарной точности с помощью модуля struct.
import struct
def twos_complement(x, bits=8):
"""Возвращает n-битный дополнительный код числа x (строкой из 0 и 1)."""
return format(x & ((1 << bits) — 1), f'0{bits}b')
print(twos_complement(-5, 8)) # 11111011
print(twos_complement(5 + (-3), 8)) # 00000010 (после отбрасывания переноса)
def float_to_ieee754_bits(x):
"""Возвращает 32-битную строку — представление x в формате IEEE 754."""
packed = struct.pack('>f', x)
return ''.join(f'{byte:08b}' for byte in packed)
print(float_to_ieee754_bits(5.5))
Функция twos_complement использует побитовую операцию И с маской (1<<bits)−1, чтобы оставить только младшие bits разрядов результата — это программный эквивалент отбрасывания «лишнего» переноса из примера 2. Функция float_to_ieee754_bits упаковывает вещественное число в 4 байта по стандарту IEEE 754 (символ '>f' означает big-endian, float одинарной точности) и переводит каждый байт в двоичную строку — результат должен совпасть с ответом примера 3.
Типичные ошибки
Частая ошибка — путать прямой, обратный и дополнительный коды и, например, записывать отрицательное число в прямом коде там, где по условию задачи требуется дополнительный. Вторая ошибка — забывать про смещение (127 для одинарной точности) при вычислении порядка числа в формате IEEE 754: порядок хранится не как есть, а увеличенным на смещение, чтобы избежать отдельного кодирования его знака. Третья ошибка — заявлять, что диапазон n-битных чисел со знаком симметричен относительно нуля: на самом деле отрицательных значений на единицу больше положительных (диапазон от −2^(n−1) до 2^(n−1)−1), потому что ноль «занимает» одно из неотрицательных значений.
Краткий словарь терминов
Прямой код — представление числа со знаком, в котором старший бит хранит знак, а остальные биты — абсолютную величину числа.
Обратный код — представление отрицательного числа, получаемое инвертированием всех битов (кроме знакового) его прямого кода.
Дополнительный код — представление отрицательного числа, получаемое прибавлением 1 к обратному коду; используется для сведения вычитания к сложению.
Мантисса — значащие цифры числа с плавающей точкой, определяющие его точность.
Порядок (экспонента) — степень основания системы счисления в представлении числа с плавающей точкой, определяющая его масштаб.
IEEE 754 — международный стандарт представления чисел с плавающей точкой в памяти компьютера.
Заключение
Представление чисел в памяти компьютера подчинено строгим двоичным форматам: целые числа со знаком практически всегда хранятся в дополнительном коде, сводящем вычитание к сложению, а вещественные числа — в формате с плавающей точкой (стандарт IEEE 754), где мантисса отвечает за точность, а порядок — за диапазон представимых величин. Понимание этих форматов объясняет, почему компьютерная арифметика имеет свои особенности и ограничения — фиксированный диапазон целых чисел и ограниченную точность вещественных. В следующей теме мы перейдём от представления чисел к формальному аппарату алгебры логики, лежащему в основе работы самих вычислительных устройств.



