Меню

Главная

Статистика

 

 


Упражнение #1.

Постройте таблицу сложения для троичной уравновешенной системы счисления.

Что нам дают все эти рассуждения об операциях в уравновешенных системах счисления? Оказывается, понятие дополнение актуально и для "обычных" позиционных нумераций, когда речь идет об отрицательных числах. Так, если отрицательное число -S записано в системе счисления с алфавитом At, и занимает m разрядов, то его дополнение определяется как tm-S.

Располагая m-разрядным диапазоном, имеющим мощность tm, половину его предоставим положительным числам, включая 0, и половину - отрицательным. При таком подходе можно оперировать положительными и отрицательными числами, чей модуль не превосходит tm-1 (за исключением самого числа tm-1, взятого со знаком '+'). Положительные числа 0 .. tm-1-1 останутся на своих местах, а отрицательные - из диапазона -tm-1 .. -1 - будут представлены своими дополнениями и попадут в диапазон tm-1 .. tm-1. Например, для числа -2510 (t=10; m=2) его дополнением является (102-25)10=7510.

Упражнение #2.

Как выглядит дополнение для числа -12310 в 4-й, 8-й, 10-й, 16-й системах счисления при m=4, 8?

Особенно удобным оказывается использование описанного выше механизма для компьютерной арифметики, базирующейся на двоичной системе счисления. Можно, конечно, осуществлять перевод из формы представления "отрицательное число -S2" в форму "дополнение 2m-S2" непосредственно, но тогда приходится использовать операцию "вычитание", а мы-то как раз хотим от нее избавиться. Оказывается, есть возможность несложного преобразования из обычной формы представления в дополнительный код и обратно, без использования вычитания. Остановимся на этом подробнее.

Для хранения целых чисел в памяти выделяется фиксированное число двоичных разрядов (бит = bit = binary digit) - обычно это степень 2.

Рассмотрим, для простоты, самый компактный вариант хранения - 8-битный. Такой однобайтный диапазон допускает 28 различных возможных значений. Если использовать его "почти симметрично" для положительных и отрицательных чисел, то мы располагаем диапазоном 0..127 для положительных чисел (включая "неотрицательный 0") и, соответственно, -128..-1 - для отрицательных.

Нумеруем биты в байте от 0 до 7 - "справа налево", если рассматривать их в привычной для нас форме, - в соответствии со степенями 2.

Размещаем в байте абсолютную величину числа в двоичной форме - то есть его двоичный код. Если теперь в старший бит - то есть, 7-й - поместить '0' (в роли знака "плюс") либо '1' (в качестве "минуса" ) то полученное представление называется прямым двоичным кодом. Нетрудно заметить, что положительное число, превосходящее 12710, "залезет" в знаковый бит и, соответственно, код окажется неверным. Кстати говоря, число -12810 в битах 0..6 также не поместится, и будет в прямом коде выглядеть как '10000000', что можно прочесть и как "-010".

Роль старшего бита здесь двоякая: кроме функции "знака", этот бит, если рассматривать содержимое байта как положительное число, соответствует степени 27, то есть помещает прямой код соответствующего отрицательного числа в диапазон 12810 .. 25510.

Далее, - если "обнаруживается", что прямой код соответствует отрицательному числу (о чем свидетельствует именно 7-й бит), - инвертируем (заменой '0' на '1' и наоборот) все разряды, кроме знакового, и получаем обратный двоичный код. Фактически, так формируется число, дополняющее абсолютную величину исходного до 27-1 (что происходит для числа -12810, проанализируйте сами) - его называют еще двоичным дополнением со сдвигом.

Наконец, после добавления к обратному коду 1, получается дополнительный двоичный код. (Для -12810 прямой и дополнительный коды совпадают.)

Пример #1.

Число 2510, размещаемое в одном байте, будет выглядеть как 000011012. Соответственно, -2510 в прямом ко де равно 100011012. Инвертируя, получаем обратный код 111100102.

Добавляя затем 1, переходим к дополнительному коду 111100112.

Нетрудно заметить, что сложение 2510 и -2510 даст в результате 0. Лишний, 8-й бит, получающийся при переполнении, физически не с уществует, что нас вполне устроит.

Впрочем, в зависимости от архитектуры конкретной ЭВМ и/или используемого программного обеспечения, факт переноса единицы из старшего разряда влево можно фиксировать в специальном флаге переполнения. (Например, в системе программирования Borland Pascal можно установить контроль за диапазоном значений с помощью директивы $R+.) И далее, продолжая вычисления в рамках компьютерной программы, вызвавшей указанное изменение флага, можно учитывать его состояние.

Итак, вводимые для обработки десятичные числа переводятся в двоичный дополнительный код и в таком виде затем обрабатываются. Но, проведя необходимую обработку, неплохо бы еще "вернуться" от представления в дополнительном коде к прямому, чтобы перевести результат в привычную для пользователя компьютера 10-ную нумерацию. Как это сделать?

Если знаковый бит дополнительного кода содержит 1 (то есть, число отрицательное), то для результата выводится знак "минус", затем следует инвертировать разряды, получая обратный код, а затем вновь добавить 1, что приведет нас к прямому коду абсолютной величины двоичного числа.

Таким образом, манипулируя двоичными числами в дополнительных кодах, мы избавляемся, как и стремились, от операции "вычитание".

Убедимся в "дееспособности" алгоритма на том же примере.

Дополнительный код числа -2510 равен 111100112.

Так как в старшем разряде стоит 1, то число - отрицательное.

Инвертируя разряды 0..6, получим обратный код 100011002.

Добавляя 1, переходим к прямому коду абсолютной величины 100011012.

В результате имеем число -2510.

Укажу еще, что, при наличии 0 в знаковом бите, описанные выше манипуляции не производятся, поскольку число "распознается" как положительное, то есть не требующее перевода в дополнительный двоичный код.

Упражнение #3.
a)

Как выглядят в дополнительном коде десятичные числа -127, -1, -0?

b)

Сравните представления в обратном и в дополнительном коде десятичных чисел -0 и +0.

c)

Сделайте несколько упражнений по "машинному" вычислению разностей вида a-b, подставляя на место a и b различные значения из разрешенного диапазона.

Однако вернемся к ситуации переполнения старшего из m разрядов, выделенных для представления целого числа. Рассмотрим следующий

Пример #2.

Пусть в нашем распоряжении 2 десятичных разряда (т.е. m=2), используемых только для неотрицательных значений (диапазон 0..99), и осуществляется сложение чисел 5610+7810. Очевидно, вместо "правильного" ответа 13410 мы получим 3410. С точки зрения обычной арифметики, это соответствует получению целочисленного остатка от деления числа 13410 на мощность выделенного диапазона: (134 mod 100)10.

Кстати говоря, когда в математике идет речь о подобном механизме, называемом модульной арифметикой, часто используют запись такого вида: mod (134, 100).

Понять, что здесь происходит, несложно, если представить себе, что числа от 0 до 9910 выписаны друг за другом на отрезке ленты, а затем концы склеены так, что получится кольцо . Соответственно, после числа 9910 будет следовать 0.

Теперь посмотрим, как работает модульная арифметика в двоичной нумерации, но пока без использования дополнительных кодов. При m=8 (1 байт) тот же пример в "двоичном воплощении" выглядит следующим образом:
5610+7810=001110002 +010011102=100001102,
т.е. 13410 и "все в порядке".

Если же мы используем выделенный байт для интервала -12810 .. 12710, то ситуация существенно меняется, поскольку полученный двоичный код содержит 1 в старшем бите и потому рассматривается как дополнительный. Для вывода результата в десятичной форме он должен быть преобразован в соответствии с описанным выше алгоритмом:
100001102(доп. код)Þ111110012 (обр. код)Þ111110102(пр. код)
- и в качестве ответа получаем -12210, что нас вряд ли устроит. Естественно: выделенный диапазон в 1 байт и не способен вместить правильный результат (число 13410), превышающий по модулю число 12710.

Назад

обслуживание пожарной сигнализации, спринклерное пожаротушение. диагностика мерседес. изготовление каталогов