Во время изучения курса «Архитектура ЭВМ и язык ассемблера» практические примеры выполняются на базе архитектуры Intel x86, которая опирается на двоичную систему счисления. Базовые сведения по системам счисления приведены в материале
Для понимания способов представления чисел в ЭВМ можно ознакомиться со следующими материалами:
Также ниже дано краткое пояснение.
представление в прямом коде (с отдельным флагом знака числа) представление в дополнительном коде (как в Intel x86) |
Интерпретация значения | ||
Байт (BYTE) | без знака | со знаком |
|
|
|
Слово (WORD) | без знака | со знаком |
|
|
|
Двойное слово (DWORD) | без знака | со знаком |
|
|
|
Интерпретация значения | ||
Байт (BYTE) | без знака | со знаком |
|
|
|
Слово (WORD) | без знака | со знаком |
|
|
|
Двойное слово (DWORD) | без знака | со знаком |
|
|
|
Для архитектуры процессора наиболее оптимальной позиционной системой счисления является та, основание которой ближе к числу e. Поэтому наиболее подходящими кандидатами являются троичная и двоичная система счисления.
1 | 0 | 1 | 1 | 2 | ... | 1 | 2 | 1 |
Троичные системы счисления не получили распространения (существовали единичные образцы троичных ЭВМ) из-за сложности производства элементной базы, поэтому подавляющее число ЭВМ работают с числами в двоичной системе счисления.
0 | 1 | 1 | 0 | 0 | ... | 0 | 0 | 1 |
b0 | b1 | b2 | b3 | b4 | ... | bk−2 | bk−1 | bk |
В машинном представлении один двоичный разряд называется «бит» (от английского «BInary digiT» — bit, двоичная цифра). Один бит хранит мало информации, поэтому в оперативной памяти ЭВМ отдельные биты группируются в ячейки памяти, каждая из которых имеет свой адрес (или условный номер).
ячейка0
|
ячейка1
|
. . . |
ячейкаN
|
|||||||||||||||||||||||||||||||
0 → адреса ячеек → N |
Таким образом, ячейка является минимально адресуемым объектом оперативной памяти ЭВМ, и чтобы прочитать или изменить отдельный бит в оперативной памяти, требуется прочитать или изменить соответствующую ячейку памяти целиком. Размер ячеек памяти (то есть количество бит в каждой ячейке) определяется архитектурой ЭВМ.
Группа из нескольких бит называется «байт» (от английского «BinarY digiT Eight» — byte). В большинстве случаев, байт состоит из 8 бит, но бывают и другие реализации, например: 6 или 7 бит. Поэтому когда надо отличить «правильный» 8-битовый байт от «неправильного», встречается термин «октет». В архитектуре Intel x86 оперативная память состоит из 8-битовых ячеек, поэтому для хранения одного 8-битового байта достаточно одной ячейки памяти.
Восемью двоичными разрядами можно описать 256 различных значений от 0 до 255. Для расширения диапазона обрабатываемых значений байты группируются в «слова» (два байта или 16 бит), «двойные слова» (четыре байта или 32 бита) и далее:
Понятно, что для обработки текстов в латинском и кириллическом алфавите достаточно выделять для хранения одной буквы по одному байту. Но для языков, набор знаков которых превышает 256, однобайтовой кодировки символов будет недостаточно.
С неотрицательными числами примерно такая же ситуация. То есть, по необходимости, используются либо байты, либо слова, либо двойные слова, либо четверные и т.д. Но далее встает вопрос о представлении отрицательных чисел. Есть варианты, например:
На практике применяют второй вариант, который не только эффективно использует память, но и позволяет задействовать бит знака числа при работе с беззнаковыми неотрицательными числами. Если значение интерпретируется как число без знака, то бит знака числа трактуется как дополнительный разряд самого числа.
Таким образом получается, что при задействовании n битов памяти для обработки чисел их значения в диапазоне [0, 2n − 1 − 1] будут представлены в памяти одинаковым набором двоичных разрядов как для знаковых чисел, так и для беззнаковых, так как бит знака числа будет равен нулю. А беззнаковые значения в диапазоне [2n − 1, 2n − 1] будут неверно интерпретироваться в виде знаковых. И, наоборот, знаковые значения в диапазоне [−2n − 1, 2n − 1 − 1] будут неверно интерпретироваться в виде беззнаковых.
Соответственно, нужны разные наборы арифметико-логических команд и разные наборы команд ввода-вывода для знаковых и беззнаковых чисел, чтобы корректно интерпретировать старший бит в двоичном представлении чисел.
Тем не менее, есть способ, позволяющий для часто используемых операций сложения и вычитания обойтись единственным вариантом команд (остальные команды всё равно должны быть в двух комплектах). Для этого во многих архитектурах ЭВМ (и в архитектуре Intel x86, в частности) применяется двоичное представление в «дополнительном коде» для отрицательных значений:
Стоит помнить, что знаковые диапазоны для положительных и отрицательных чисел в дополнительном коде не симметричны. Поскольку «ноль» не входит в положительные числа, поэтому правая граница положительных значений на единицу меньше модуля левой границы.
Графически дополнительный код можно представить, как если бы отрезок [0, 2n] свернуть в кольцо и поверх него наложить отрезок [−2n − 1, 2n − 1 − 1]. Ниже приведён пример иллюстрации этого представления для 8-битового кода:
-127 129 | -128 128 | 127 127 | 126 126 | ||
-126 | 130 | 125 | 125 | ||||
... | ... | ... | ... | ||||
-3 | 253 | 3 | 3 | ||||
-2 | 254 | 2 | 2 | ||||
255 -1 | 0 0 | 1 1 |
Можно убедиться, что представление в дополнительном двоичном коде позволяет использовать одни те же команды для сложения-вычитания как для знаковых, так и для беззнаковых чисел.
Если выполянется условие | x | < 2n − 1, | y | < 2n − 1, тогда знаковые числа x и y можно представить в дополнительном коде в n-битной ячейке. В этом случае результат сложения чисел x и y, записанных в дополнительном коде, будет эквивалентен результату сложения этих чисел в беззнаковой интерпретации. При проверке надо помнить, что результат операций вычисляется по модулю 2n, потому что в n-битной ячейке можно хранить только n двоичных разрядов.
Большинство ЭВМ (за некоторым исключением) размещают данные в памяти в порядке возрастания старшинства: младшие значения размещают в ячейках с меньшим адресом, а старшие значения — в ячейках с большим адресом (LE — Little Endian). Такой подход упрощает обработку длинных данных, занимающих несколько ячеек памяти подряд.
|
X
|
X + 1
|
. . . |
X + M
|
||||||||||||||||||||||||||||||||
0 → адреса ячеек → N |
Например, программа для сложения (или вычитания) двух длинных целых чисел Z = X + Y, занимающих 16 ячеек памяти, будет представлять собой цикл из 16 итераций, в каждой из которых будет производиться арифметическая операция с очередной парой ячеек памяти с учетом признака переполнения (OF).
|
|
|
. . . |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
(Z) = (X) + (Y)
|
(Z + 1) = OF + (X+1) + (Y+1)
|
. . . |
(Z + 15) = OF + (X+15) + (Y+15)
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0 → адреса ячеек → N |
Максимальный эффект достигается тогда, когда требуется обрабатывать последовательность таких длинных чисел, которые не обязательно находятся в оперативной памяти ЭВМ или в устройстве с произвольным доступом. Действительно, если входные данные сплошным потоком поступают из устройства с последовательным доступом, например, из такого, как линия связи, магнитная лента или оптический диск, то, получив очередную ячейку данных, программа имеет возможность сразу её обработать, не дожидаясь прихода следующих данных.
А теперь внимание. Надеюсь, вы заметили в приведённых выше иллюстрациях, что адреса ячеек на иллюстрациях расположены в порядке возрастания слева-направо. Да, и биты тоже изображены в порядке возрастания старшинства разрядов слева-направо: слева — младший бит, а старший — справа. Но на письме мы записываем числа иначе. Сначала мы пишем старшие разряды, а потом младшие. Так вот, чтобы не было путаницы, и чтобы не тратить время на переворот записи числа в уме, для иллюстрации работы с числами ячейки памяти изображают в порядке возрастания адресов справа-налево. То есть справа изображают ячейки с младшими адресами, а слева — со старшими.
При таком подходе иллюстрация представления числа 46 901 (в двоичной записи — 1011 0111 0011 01012, в шестнадцатеричной записи — B7 3516) по адресу X в ячейках размером в байт будет выглядеть так:
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||
N ← адреса ячеек ← 0 |
А представление числа 1 957 227 809 (111 0100 1010 1000 1110 1101 0010 00012, 74 A8 ED 2116) по адресу Y будет выглядеть так:
|
|
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
N ← адреса ячеек ← 0 |