Особенности сложения и вычитания целых чисел в ПК




Беззнаковые числа складываются как обычно, только в двоичной системе счисления. Однако здесь есть одна проблема: что делать, если сумма получится очень большой - такой, что она не умещается в ячейке? Например, если при ячейке размером в 8 битов мы складываем 250 и 10, то получим число 260 (100000100b), которое не "влезает" в ячейку.

В некоторых ЭВМ в такой ситуации фиксируется ошибка и на этом прекращается выполнение программы. Однако в ПК реакция иная: ошибка не фиксируется, левая единица (единица переноса) отбрасывается и в качестве ответа выдается искаженная сумма (в нашем примере ответом будет байт 00000100b, т. е. число 4). Но зато в флаг переноса CF записывают 1. Это сигнал о том, что получилась неправильная сумма (если переноса не было, то в CF записывают 0). Затем можно проанализировать этот флаг (подходящие средства для этого есть) и "поймать" такую ошибку.

Такое суммирование с отбрасыванием единицы переноса в математике называется суммированием по модулю 2k (k - размер ячейки), при этом в флаге CF фиксируется, был ли перенос:

При вычитании беззнаковых целых чисел также возникает проблема: что делать, если при вычитании х-у число х меньше числа у? Ведь в этом случае получится отрицательная разность, а это уже вне области беззнаковых чисел.

В ПК поступают следующим образом: при х >= у выполняется обычное вычитание, но если х < у, тогда числу х дается "заем" единицы (к числу х прибавляется величина 2k) и только после этого производится вычитание. Полученное таким образом число и объявляется разностью. Например, при k=8 вычитание 1-2 происходит таким образом:

1 – 2->(28+1) - 2 = (256+1) - 2 = 257 - 2 = 255

(в двоичной системе замена 1 на 256+1 - это замена 00000001 на 100000001, т. е. приписывание 1 слева) и именно число 255 объявляется результатом вычитания 1-2. При этом ошибка не фиксируется, зато в флаг переноса CF заносится 1, что сигнализирует о заеме единицы, о неправильном результате (при х >= у в CF заносится 0).

Выполняемое так вычитание в математике называют вычитанием по модулю 2k, при этом фиксируется, был ли заем:

Итак, в ПК сложение и вычитание беззнаковых целых чисел - это на самом деле сложение и вычитание по модулю 2k, где k - размер ячеек. Причем появление после операции значения 1 в флаге переноса CF свидетельствует о том, что выданный ответ неправильный.

Теперь рассмотрим сложение и вычитание знаковых чисел. Оказывается, если целые со знаком представлены в дополнительном коде, то складывать и вычитать их можно по алгоритмам для беззнаковых чисел. Делается это так: дополнительные коды знаковых операндов рассматривают как числа без знака и в таком виде их складывают или вычитают, а полученный результат затем рассматривают как дополнительный код знакового ответа.

Пример (при ячейке в 8 битов). Пусть надо сложить +3 и -1. Их дополнительные коды - это 3 и (256-1)=255. Складываем их как числа без знака: 3+255 (mod 256) = 258 (mod 256) = 2. Теперь величина 2 рассматривается как дополнительный код ответа, поэтому получается ответ +2.

Другой пример. Пусть надо сложить -3 и +1. Дополнительные коды этих знаковых чисел: (256-3)=253 и 1. Складываем их как беззнаковые числа: 253+1 (mod 256) = 254. Теперь, рассматривая эту величину как дополнительный код ответа, получаем результат -2 (254=256-2).

Из сказанного следует, что в ЭВМ, где знаковые числа представляются в дополнительном коде, не нужны разные машинные команды для сложения и вычитания беззнаковых и знаковых чисел, достаточно и одного набора этих команд. (В этом важное преимущество дополнительного кода над другими способами представления знаковых чисел.)

Однако не все так просто при сложении и вычитании знаковых чисел, здесь есть свои неприятности. Напомним, что при размере ячеек в 8 битов в дополнительном коде представляются только числа от -128 до +127. Рассмотрим, к примеру, сложение знаковых чисел +127 и +2. Складывая их как беззнаковые числа 127 и 2, получаем величину 129, которую теперь надо рассмотреть как дополнительный код ответа: поскольку 129=256-127, то суммой должно быть признано число -127. Таким образом, складывая два положительных числа, мы получили отрицательное число!

Почему так произошло? При представлении чисел (размером в байт) в дополнительном коде левый разряд является знаковым, а на модуль числа отводится 7 правых разрядов. У нас же получился ответ 129=10000001Ь, модуль которого не вмещается в эти 7 разрядов, поэтому модуль и "залез" в знаковый разряд, изменив его на противоположный.

Такое налезание модуля (мантиссы, цифровой части) числа на знаковый разряд называют "переполнением мантиссы". В общем случае оно происходит, если складываются числа одного знака и настоящая сумма оказывается вне диапазона представимых знаковых чисел ([-128, +127] при k=8). Переполнение мантиссы фиксируется в флаге переполнения OF: он получает значение 1, если было переполнение, и значение 0 иначе. Таким образом, при OF=0 результат правильный, а при OF=1 - неправильный, однако эта ошибка не фиксируется и "поймать" ее можно только последующим анализом флага OF.

Аналогичное переполнение мантиссы возможно и при вычитании. Например, при вычитании (+127)-(-2) = 127+2 получаем 129, а это дополнительный код числа -127, которое и выдается как результат вычитания, хотя истинной разностью является число 129. В общем случае переполнение мантиссы происходит, если вычитаются числа разных знаков и настоящая разность оказалась вне диапазона представимых знаковых чисел. И здесь факт переполнения фиксируется в флаге OF: он получает значение 1, если было переполнение мантиссы и результат операции неправильный, и значение 0, если не было переполнения и ответ правильный.

Итак, при сложении и вычитании как беззнаковых, так и знаковых чисел возможны особые случаи, когда настоящий (в математическом смысле) результат выходит за диапазон представимых чисел, и тогда результат искажается. Такое искажение результата фиксируется в флагах CF и OF. Распознать такую ошибку можно лишь последующим анализом этих флагов.

И еще одно замечание. Поскольку сложение и вычитание беззнаковых и знаковых чисел производятся по одним и тем же алгоритмам и поскольку ПК заранее не знает, какие именно числа он складывает или вычитает, то при выполнении этих операций ПК одновременно фиксирует в флагах CF и OF особенности операций для обоих классов чисел. Какие именно числа складываются вычитаются), знает только автор программы, он и должен решать, на какой из этих двух флагов следует реагировать. Если он считает, что складываются безнаковые числа, то для него представляет интерес флаг CF (был ли перенос) и безразличен флаг OF, но если, по его мнению, складываются знаковые числа, то он должен интересоваться флагом OF (было ли переполнение мантиссы) и не должен обращать внимание на флаг CF.

При сложении и вычитании чисел меняются также флаг нуля ZF и флаг знака SF. Флаг ZF получает значение 1, если результат оказался нулевым, и значение 0, если результат ненулевой; этот флаг представляет интерес при работе как со знаковыми, так и беззнаковыми числами. В флаг же SF заносится знаковый (самый левый) бит результата; этот флаг полезен при работе со знаковыми числами, т. к. он получает значение 1, если результат оказался отрицательным, и значение 0 иначе.

Примеры (ячейки размером в байт):

9 - 9 = 0 = 00000000b = 8-9 -> ZF = 1, SF = 0

8 - 9 = -1 = llllllllb -> ZF = 0, SF = 1

9 - 8 = -1 " 0000000lb -> ZF = 0, SF = 0



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-02-16 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: