Как сложить 2 двоичных числа в ассемблере

от admin

1.7.2. Сложение двоичных чисел в ЭВМ

При сложении на основе m-разрядного АЛУ чисел Х и Y необходимо, чтобы отсутствовало переполнение, т.е. (X +Y) < 2 m . Суммирование осуществляется в МП 80х86 по команде ADD .

Пример 1.3 (далее примеры даны для 8-битовых чисел).

1101 Переносы, признак С = 0 X = 00000101

Поразрядное суммирование для i-го разряда осуществляется с учетом переноса C i из предыдущего (более младшего) разряда:

C i+1 S i = X i + Y i + C i ,

где C i+1 – выходной перенос, S i – младший бит суммы X i + Y i + C i .

Сложение целых двоичных чисел со знаком

Производится в ДК. При этом необходимо, чтобы исходные числа были представлены в ДК. Результат сложения выдается в ДК.

Сложение в ДК производится по правилу: сумма дополнительных кодов слагаемых равна ДК суммы

[X] ДК + [Y] ДК = [X + Y] ДК при выполнении трех условий:

1) отсутствует переполнение ½ X + Y ½ < 2 m–1 ;

2) знаковые разряды слагаемых участвуют в операции суммирования по тем же правилам, что и значащие цифры;

3) единица переноса из знакового разряда суммы отбрасывает-

Х= +17 = 00010001 → + [X] ДК = + 00010001 Y= –9 = –00001001 → [Y] ДК = 11110111 [X + Y] ДК = 00001000

Проверка: X + Y = +00001000 = +2 3 = +8

X = –17 = –00010001 → [X] ДК = + 11101111

Y = +9 = +00001001 → [Y] ДК = 00001001 [X + Y] ДК = 11111000

Для проверки переведем [X + Y] ДК в X + Y. Получим: X + Y = = –00001000 = –8.

При сложении X и Y (пример 2.5) формируются также признаки результата [X + Y] ДК , а именно Z = 0, S = 1, C = 0, V = 0, P = 0.

Пример 1.6. Сложить числа, представленные в 16-ричной СС.

X = –11 16 = → + [X] ДК = + EF

Y = +09 16 = → [Y] ДК = 09

[X + Y] ДК = F8 → Проверка: X + Y= –(F8 + 1) = –(07 + 1) = –08.

Таблица сложения 16-ричных цифр (символов) приведена в приложении 6.

1.7.3. Вычитание двоичных чисел в ЭВМ

Вычитание целых двоичных чисел без знака

— 1 Заемы X = 17 = — 00010001

Y = 09 = 00001001

X – Y = 00001000 → (8)

Правило вычитания двоичных цифр:

Операция вычитания над цифрами X i и Y i чисел X и Y производится с учетом входного заема C i по формуле:

C i+1 r i = X i – Y i – C i ,

где C i+1 – выходной, r i – младший бит получаемой разности X i – Y i – C i .

Вычитание целых двоичных чисел со знаком

Вычитание производится в дополнительном коде, поэтому исходные операнды заранее представляются в этом коде. Результат также получается в ДК.

В микропроцессорах 80х86 вычитание осуществляется по команде вычитания SUB в соответствии с формулой

[X] ДК – [Y] ДК = [X – Y] ДК при выполнении трех условий:

2) знаковые разряды операндов участвуют в операции по тем же правилам, что и значащие;

3) единица заема С из результата отбрасывается.

— 1111 Заемы, С=1 X = 13 = 00001101 ® [X] ДК = — 00001101

Y = –7 = –00000111 ® [Y] ДК = 11111001

[X – Y] ДК = 00010100 Проверка ® X – Y = +20.

1.7.4. Выполнение в ЭВМ логических операций

Логические операции конъюнкции, дизъюнкции и другие выполняются в ЭВМ над логическими переменными:

X = X m–1 X m–2 …X 1 X 0 – логическая переменная X, Y = Y m–1 Y m–2 …Y 1 Y 0 – логическая переменная Y,

Отметим, что логическая переменная, как машинный элемент информации, представляется в виде двоичного слова.

1. Конъюнкция Z ← X &Y

Реализуется с помощью команды AND путем выполнения поразрядных операций конъюнкции Z i = X i & Y i над соответствующими битами X i и Y i с получением бита результата Z i в соответствии с таблицей:

Логическая схема «И»

Поразрядная операция Z i = X i & Y i осуществляется в АЛС с помощью логической схемы «И».

Y = & 01101011 Z = 00001011

Переносы между разрядами результата отсутствуют. Вследствие этого признак С = 0, остальные признаки формируются. Часто операцию конъюнкции называют операцией маскирования . В этом случае одну из переменных называют маской . С помощью операции маскирования можно:

1) выделить один бит или группу битов слова,

2) определить модуль числа ï Х ï ,

3) выявить знак числа.

X=X 7 X 6 X 5 X 4 X 3 X 2 X 1 X 0

Y= 0 1 1 1 1 1 1 1 – маска для определения ï Х ï

Z = X & Y = 0 X 6 X 5 X 4 X 3 X 2 X 1 X 0

Частным случаем конъюнкции является операция тестирования X &Y . При ее выполнении устанавливаются только признаки результата X &Y без формирования его значения. Эта операция выполняется микропроцессором с помощью команды TEST.

2. Дизъюнкция Z ← X V Y

Логическая схема «ИЛИ»

Операция выполняется по команде OR и часто используется для образования из частей слова нового слова.

Поразрядная операция Z i = X i V Y i осуществляется в АЛС с помощью логической схемы «ИЛИ».

3. Сложение по модулю два (неравнозначное ИЛИ) Z ¬ X Å Y

Операция часто используется для сброса в 0 регистра, определения знака произведения или частного путем сложения по модулю два знаков операндов. Знак Z = Знак X Å Знак Y.

4. Инверсия: X ¬ X

5. Сравнение X – Y

При сравнении формируются только признаки результата вычитания X – Y, а сама разность не фиксируется. Данная операция осуществляется путем выполнения команды СМР .

Различают следующие типы сдвигов: логические, арифметические и циклические.

При логическом сдвиге слова влево содержимое всех его бит, например слова А = А 7 А 6 . А 0 перемещается влево на один разряд.

Освобождающийся разряд А 0 заполняется нулем. Выдвинутый бит А 7 чаще всего размещается в триггере переноса С.

Логический сдвиг влево

0 0 0 0 0 0 1 1

0 0 0 0 0 1 1 0

после сдвига А = 6

Сдвиг числа влево на один разряд соответствует умножению значения А на два: A ¬ 2 × A.

Сдвиг числа вправо на один бит равносилен операции деления: A ¬ A/2.

Логический сдвиг вправо

0 0 0 0 1 1 0 0

до сдвига А = 12

0 0 0 0 0 1 1 0

после сдвига А = 6

Арифметический сдвиг влево чисел в ДК полностью совпадает с логическим сдвигом влево.

При арифметическом сдвиге вправо содержимое старшего разряда не изменяется. Например, для чисел в ДК:

после сдвига [X] ДК = 11111110

При арифметическом сдвиге выдвинутый бит размещается в триггере переноса С.

Циклические сдвиги через триггер переноса

При данном виде сдвига слова выдвинутый бит размещают в триггере переноса С, а в освобождающийся разряд слова А переносят бит из триггера переноса.

Сдвиг вправо через С

A i ← A i+1 , С ← A 0 , A 7 ← С

Сдвиг влево через С

A i ← A i-1 , A 0 ← С, С ← A 7

Циклические сдвиги минуя триггер переноса

При данном виде сдвига слова А выдвинутый бит размещают в триггере переноса С, а в освобождающийся разряд слова А помещают выдвинутый бит из регистра А.

Если в системе команд отсутствует операция логического или арифметического сдвига, то любой сдвиг можно осуществить с помощью циклических сдвигов. Эти сдвиги также используются для организации сдвига слов повышенной длины.

2. ПРИНЦИПЫ ДОСТУПА К ПАМЯТИ. ФОРМАТЫ КОМАНД И РЕЖИМЫ АДРЕСАЦИИ

2.1. Регистры и модели доступа к памяти. Поддержка многозадачности

в защищенном режиме работы МП

2.1.1. Регистровая модель процессора 80х86

При разработке программ на языке ассемблера целесообразно представлять процессор в виде его регистровой модели как одной из важных составляющих его программной архитектуры. Эта модель содержит набор программно доступных регистров процессора (или МП), содержимое которых пользователь может изменять программно с помощью команд МП. Добавляя к регистрам МП адресуемое множество ячеек (регистров) памяти и портов ввода-вывода (в/в), строится регистровая модель компьютера в целом.

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

На рисунке 2.1 приведена регистровая (программная) модель МП Intel 8086, регистры которого входят в состав любого 32-битового МП семейства 80х86 при его работе в реальном (R-) режиме.

В приведенной регистровой модели в зависимости от выполняемых функций выделяют следующие группы регистров.

1. Регистры данных. В зависимости от того, чем оперирует команда – словами или байтами – регистры данных можно рассматривать как четыре 16-битовых (AX, CX, BX, DX) или как восемь 8-битовых регистров (AL, AH, CL, CH, BL, BH, DL, DH). Символы L и H означают младшие и старшие байты 16-разрядных регистров.

Каждый из этих регистров МП помимо общих выполняет специализированные функции: AX, AL – аккумулятор; BX – базовый регистр для косвенной адресации памяти; CX – счетчик в операциях с цепочками; DX – указатель при косвенной адресации портов ввода/вывода.

Урок 7

Расширенные арифметические операции с целыми числами

Несмотря на то, что мы привыкли к десятичной арифметике (база 10), компьютер работает только с двоичной арифметикой (база 2). Кроме того, ввиду ограничения, накладываемого 16-битовыми регистрами, большие величины требуют специальной обработки. Данная глава дает сведения об операциях сложения, вычитания, умножения и деления для беззнаковых и знаковых данных. В главе приводятся много примеров и предупреждений о различных ловушках для опрометчивых исследователей мира микропроцессора. В следующей главе будут раскрыты операции преобразования между двоичными данными и ASCII кодами.

Сложение и вычитание

Команды ADD и SUB выполняют сложение и вычитание байтов или слов, содержащих двоичные данные. Вычитание выполняется в компьютере по методу сложения с двоичным дополнением: для второго операнда устанавливаются обратные значения бит и прибавляется 1, а затем проиCXодит сложение с первым операндом. Во всем, кроме первого шага, операции сложения и вычитания идентичны. Возможны следующие пять ситуаций:

Поскольку прямой операции память-память не существует, данная oперация выполняется через регистр. В следующем примере к содержимому слова WORDB прибавляется содержимое слова WORDA, описанных как DW:

Переполнения

Опасайтесь переполнений в арифметических операциях. Один байт содержит знаковый бит и семь бит данных, т.е. значения от -128 до +127. Результат арифметической операции может легко превзойти емкость однобайтового регистра. Например, результат сложения в регистре AL, превышающий его емкость, автоматически не переходит в регистр AH. Предположим, что регистр AL содержит шест.60, тогда результат команды

генерирует в AL суумму — шест.80. Но операция также устанавливает флаг переполнения и знаковый флаг в состояние «отрицательно». Причина заключается в том, что шест.80 или двоичное 1000 0000 является отрицательным числом. Т.е. в результате, вместо +128, мы получим -128. Так как регистр AL слишком мал для такой операции и следует воспользоваться регистром AX. В следующем примере команда CBW (Convert Byte to Word — преобразовать байт в слово) преобразует шест.60 в регистре AL в шест.0060 в регистре AX, передавая при этом знаковый бит (0) через регистр AH. Команда ADD генерирует теперь в регистре AX правильный результат: шест.0080, или +128:

Но полное слово имеет также ограничение: один знаковый бит и 15 бит данных, что соответствует значениям от -32768 до +32767. Рассмотрим далее как можно обрабатывать числа, превышающие эти пределы.

Многословное сложение

Максимальное возможное значение в регистре +32767 ограни чивает возможность компьютера для выполнения арифметических операций. Рассмотрим два способа выполнения арифметических операций. Первый способ — более прост, но специфичен, второй — сложнее, но имеет общий характер. Сумма — шест.1119C превышает емкость регистра AX. Переполнение вызывает установку флага переноса в 1. Затем выполняется сложение левых слов, но в данном случае, вместо команды ADD используется команда сложения с переносом ADC (ADd with Carry). Эта команда складывает два значения, и если флаг CF уже установлен, то к сумме прибавляется 1:

При использовании отладчика DEBUG для трассировки арифметических команд можно увидеть эту сумму 0136 в регистре AX, и обpатные значения 3601 в поле WORD3A и 9C11 в поле WORD3B. На рис.12.2 процедура E10DWD демонстрирует подход к сложению значений любой длины. Действие начинается со сложения самых правых слов складываемых полей. В первом цикле складываются правые cлова, во втором — слова, расположенные левее. При этом адреса в регистрах SI, DI и BX уменьшаются на 2. По две команда DEC выполняют эту операцию для каждого регистра. Применять команду

в данном случае нельзя, т.к. при этом будет очищен флаг переноса, что приведет к искажению результата сложения. Ввиду наличия цикла, используется только одна команда сложения ADC. Перед циклом команда CLC (CLear Carry — очистить флаг переноса) устанавливает нулевое значение флага переноса. Для работы данного метода необходимо: 1) обеспе чить смежность слов, 2) выполнять обработку справа налево и 3) загрузить в регистр CX число складываемых слов. Для многословного вычитания используется команда SBB (SuBtract with Borrow — вычитание с заемом) эквивалентная команде ADC. Заменив в процедуре E10DWD (рис.12.2) команду ADC на SBB, получим процедуру для вычитания.

Беззнаковые данные

Многие числовые поля не имеют знака, например, номер абонента, aдрес памяти. Некоторые числовые поля предлагаются всегда положительные, например, норма выплаты, день недели, значение числа ПИ. Другие числовые поля являются знаковые, так как их содержимое может быть положительным или отрицательным. Например, долговой баланс покупателя, который может быть отрицательным при переплатах, или алгебраическое число. Для беззнаковых величин все биты являются битами данных и вместо ограничения +32767 регистр может содержать числа до +65535. Для знаковых величин левый байт является знаковым битом. Команды ADD и SUB не делают разницы между знаковыми и беззнаковыми величинами, они просто складывают и вычитают биты. В следующем примере сложения двух двоичных чисел, первое число содержит единичный левый бит. Для беззнакового числа биты представляют положительное число 249, для знакового — отрицательное число -7:

Двоичное представление результата сложения одинаково для беззнакового и знакового числа. Однако, биты представляют +251 для беззнакового числа и -5 для знакового. Таким одразом, числовое содержимое поля может интерпретироваться по разному. Состояние «перенос» возникает в том случае, когда имеется пеpенос в знаковый разряд. Состояние «переполнение» возника ет в том случае, когда перенос в знаковый разряд не создает переноса из разрядной сетки или перенос из разрядной сетки проиCXодит без переноса в знаковый разряд. При возникновении переноса при сложении беззнаковых чисел, результат получает ся неправильный:

При возникновении переполнения при сложении знаковых чисел, результат получается неправильный:

При операциях сложения и вычитания может одновременно возникнуть и переполнение, и перенос:

Умножение

Операция умножения для беззнаковых данных выполняется командой MUL, а для знаковых — IMUL (Integer MULtiplication — умножение целых чисел). Ответственность за контроль над форматом обрабатываемых чисел и за выбор подходящей команды умножения лежит на самом программисте. Существуют две основные операции умножения:

«Байт на байт». Множимое находится в регистре AL, а множи тель в байте памяти или в однобайтовом регистре. После умножения произведение находится в регистре AX. Операция игнорирует и стиpает любые данные, которые находились в регистре AH.

«Слово на слово». Множимое находится в регистре AX, а мно житель — в слове памяти или в регистре. После умножения произведение находится в двойном слове, для которого требуется два регистра: старшая (левая) часть произведения находится в регистре DX, а младшая (правая) часть в регистре AX. Операция игнорирует и стирает любые данные, которые находились в регистре DX.

В единственном операнде команд MUL и IMUL указывается множитель. Рассмотрим следующую команду:

Если поле MULTR определено как байт (DB), то операция предполагает умножение содержимого AL на значение байта из поля MULTR. Если поле MULTR определено как слово (DW), то опереция предполагает умножение содержимого AX на значение слова из поля MULTR. Если множитель находится в регистре, то длина регистра определяет тип операции, как это показанно ниже:

Беззнаковое умножение: Команда MUL

Команда MUL (MULtiplication — умножение) умножает беззна ковые числа. На рис. 12.3 в процедуре C10MUL дано три примера умножения: байт на байт, слово на слово и слово на байт. Первый пример команды MUL умножает шест.80 (128) на шест.47 (64). Произведение -ш ест.2000 (8192) получается в регистре AX. Второй пример команды MUL генерирует шест. 10000000 в регистpах DX:AX. Третий пример команды MUL выполняет умножение слова на байт и требует расширение байта BYTE1 до размеров слова. Так как предполагаются беззнаковые величины, то в примере левый бит регистра AH равен нулю. (При использовании команды CBW значение левого бита регистpа AL может быть 0 или 1). Произведение — шест. 00400000 получается в регистрах DX:AX.

Знаковое умножение: Команда IMUL

Команда IMUL (Integer MULtiplication — умножение целых чисел) умножает знаковые числа. На рис. 12.3 в процедуре D10IMUL используются те же три примера умножения, что и в процедуре C10MUL, но вместо команд MUL записаны команды IMUL. Первый пример команды IMUL умножает шест.80 (отрицатель ное число) на шест.40 (положительное число). Произведение — шест.E000 получается в регистре AX. Используя те же данные, команда MUL дает в результате шест.2000, так что можно видеть разницу в использовании команд MUL и IMUL. Команда MUL рассматривает шест.80 как +128, а команда IMUL — как -128. В результате умножения -128 на +64 получается -8192 или шест.E000. (Попробуйте преобразовать шест.Е000 в десятичный формат). Второй пример команды IMUL умножает шест.8000 (отрицатель ное значение) на шест.2000 (положительное значение). Произведение — шест.F0000000 получается в регистрах DX:AX и представляет собой oтрицательное значение. Третий пример команды IMUL перед умножением выполняет расширение байта BYTE1 до размеров слова в регистре AX. Так как значения предполагаются знаковые, то в примере используется команда CBW для перевода левого знакового бита в регистр AH: шест.80 в pегистре AL превращается в шест.FF80 в регистре AX. Поскольку множитель в слове WORD1 имеет также отрицательное значение, то произведение должно получится положительное. В самом деле: шест.00400000 в регистрах DX:AX — такой же результат, как и в случае умножения командой MUL, которая предполагала положительные сомножители. Таким образом, если множимое и множитель имеет одинаковый знаковый бит, то команды MUL и IMUL генерируют одинаковый результат. Но, если сомножители имеют разные знаковые биты, то команда MUL вырабатывает положительный результат умножения, а команда IMUL — отрицательный. Можно обнаружить это, используя отладчик DEBUG для трассировки примеров. Повышение эффективности умножения: При умножении на степень числа 2 (2,4,8 и т.д.) более эффективным является сдвиг влево на требуемое число битов. Сдвиг более чем на 1 требует загрузки величины сдвига в регистр CL. В следующих примерах предположим, что множимое находится в регистре AL или AX:

Читать:
Как создать страницу в битриксе и привязать к меню

Многословное умножение

Обычно умножение имеет два типа: «байт на байт» и «слово на слово». Как уже было показано, максимальное знаковое значение в слове ограничено величиной +32767. Умножение больших чисел требует выполнения некоторых дополнительных действий. Рассматриваемый подход предполагает умножение каждого слова отдельно и сложение полученных результатов. Рассмотрим следующее умножение в десятичном формате:

Представим, что десятичная арифметика может умножать только двухзначные числа. Тогда можно умножить 13 и 65 на 12 раздельно, cледующим образом:

Следующим шагом сложим полученные произведения, но поскольку число 13 представляло сотни, то первое произведение в действительности будет 15600:

Ассемблерная программа использует аналогичную технику за исключением того, что данные имеют размерность слов (четыре цифры) в шестнадцатеричном формате.

Умножение двойного слова на слово. Процедура E10XMUL на рис.12.4 умножает двойное слово на слово. Множимое, MULTCND, состоит из двух слов, содержащих соответственно шест. 3206 и шест. 2521. Определение данных в виде двух слов (DW) вместо двойного слова (DD) обусловлено необходимостью правильной адресации для команд MOV, пересылающих слова в регистр AX. Множитель MULTPLR содержит шест. 6400. Область для записи произведения, PRODUCT, состоит из трех слов. Первая команда MUL перемножает MULTPLR и правое cлово поля MULTCND; произведение — шест. 0E80 E400 записывается в PRODUCT+2 и PRODUCT+4. Вторая команда MUL перемножает MULTPLR и левое слово поля MULTCND, получая в результате шест. 138A 5800. Далее выполняется сложение двух произведений следующим образом:

Так как первая команда ADD может выработать перенос, то второе cложение выполняется командой сложения с переносом ADC (ADd with Carry). В силу обратного представления байтов в словах в процессоpах 8086/8088, область PRODUCT в действи тельности будет содержать значение 8A13 8066 00E4. Программа предполагает, что первое слово в области PRODUCT имеет начальное значение 0000. Умножение «двойного слова на двойное слово». Умножение двух двойных слов включает следующие четыре операции умножения:

Каждое произведение в регистрах DX и AX складывается с соответствующим словом в окончательном результате. Пример такого умножения приведен в процедуре F10XMUL на рис. 12.4. Множимое MULTCND содержит шест. 3206 2521, множитель MULTPLR — шест. 6400 0A26. Результат заносится в область PRODUCT, состоящую из четырех слов. Хотя логика умножения двойных слов аналогична умножению двойного слова на слово, имеется одна особенность, после пары команд сложения ADD/ADC используется еще одна команда ADC, которая прибавляет 0 к значению в поле PRODUCT. Это необходимо потому, что первая команда ADC сама может вызвыть перенос, который последующие команды могут стереть. Поэтому вторая команда ADC прибавит 0, если переноса нет, и прибавит 1, если перенос есть. Финальная пара команд ADD/ADC не тредует дополнительной команды ADC, так как область PRODUCT достаточно велика для генерации окончательного результата и переноса на последнем этапе не будет. Окончательный результат 138A 687C 8E5C CCE6 получится в поле PRODUCT в обратной записи байт в словах. Выполните трассировку этого примера с помощью отладчика DEBUG.

=== Сдвиг регистровой пары DX:AX Следующая подпрограмма может быть полезна для сдвига содержимого pегистровой пары DX:AX вправо или влево. Можно придумать более эффективный метод, но данный пример представляет общий подход для любого числа циклов (и, соответственно, сдвигов) в регистре CX. Заметьте, что сдвиг единичного бита за разрядную сетку устанавливает флаг переноса.

Ниже приведен более эффективный способ для сдвига влево, не требующий организации цикла. В этом примере фактор сдвига записывается в регистр CL. Пример написан для сдвига на 4 бита, но может быть адаптирован для других величин сдвигов:

Деление

Операция деления для беззнаковых данных выполняется командой DIV, a для знаковых — IDIV. Ответственность за подбор подходящей команды лежит на программисте. Существуют две основные операции деления: Деление «слова на байт». Делимое находится в регистре AX, а делитель — в байте памяти или а однобайтовом регистре. После деления остаток получается в регистре AH, а частное — в AL. Так как однобайтовое частное очень мало (максимально +255 (шест.FF) для беззнакового деления и +127 (шест.7F) для знакового), то данная операция имеет ограниченное использование.

Деление «двойного слова на слово». Делимое находится в регистровой паре DX:AX, а делитель — в слове памяти или а регистре. После деления остаток получается в регистре DX, а частное в регистре AX. Частное в одном слове допускает максимальное значение +32767 (шест.FFFF) для беззнакового деления и +16383 (шест.7FFF) для знакового.

В единственном операнде команд DIV и IDIV указывается делитель. Рассмотрим следующую команду:

Если поле DIVISOR определено как байт (DB), то операция предполагает деление слова на байт. Если поле DIVISOR определено как слово (DW), то операция предполагает деление двойного слова на слово. При делении, например, 13 на 3, получается разельтат 4 1/3. Частное есть 4, а остаток — 1. Заметим, что ручной калькулятор (или программа на языке BASIC) выдает в этом случае результат 4,333…. Значение содержит целую часть (4) и дробную часть (,333). Значение 1/3 и 333… есть дробные части, в то время как 1 есть остаток от деления.

Беззнаковое деление: Команда DIV

Команда DIV делит беззнаковые числа. На рис.12.5 в процедуре D10DIV дано четыре примера деления: слово на байт, байт на байт, двойное слово на слово и слово на слово. Первый пример команды DIV делит шест.2000 (8092) на шест.80 (128). В результате остаток 00 получается в регистре AH, а частное шест.40 (64) — в регистре AL. Второй пример команды DIV выполняет прежде расширение байта BYTE1 до размеров слова. Так как здесь предполагается беззнаковая величина, то в примере левый бит регистра AH равен нулю. В результате деления остаток — шест. 12 получает ся в регистре AH, а частное шест.05 — в регистре AL. Третий пример команды DIV генерирует остаток шест. 1000 в регистре DX и частное шест. 0080 в регистре AX. В четвертом примере команды DIV сначала выполняется расширение слова WORD1 до двойного слова в регистре DX. После деления остаток шест.0000 получится в регистре DX, а частное шест. 0002 — в регистре AX.

Знаковое деление: Команда IDIV

Команда IDIV (Integer DIVide) выполняет деление знаковых чисел. На рис.12.5 в процедуре E10IDIV используются те же четыре примера деления, что и в процедуре D10DIV, но вместо команд DIV записаны команды IDIV. Первый пример команды IDIV делит шест.2000 (положительное число) на шест.80 (отри цательное число). Остаток от деления — шест. 00 получается в регистре AH , а частное — шест. C0 (-64) — в регистре AL. Команда DIV, используя те же числа, генерирует частное +64. Шестнадцатиричные результаты трех остальных примеров деления приведены ниже:

Только в примере 4 вырабатывается такой же результат, что и для команды DIV. Таким образом, если делимое и делитель имеют одинаковый знаковый бит, то команды DIV и IDIV генерируют одинаковый pезультат. Но, если делимое и делитель имеют разные знаковые биты, то команда DIV генерирует положи тельное частное, а команда IDIV — отрицательное частное. Можно обнаружить это, используя отладчик DEBUG для трасси ровки этих примеров. Повышение производительности. При делении на степень числа 2 (2, 4, и т.д.) более эффективным является сдвиг вправо на требуемое число битов. В следующих примерах предположим, что делимое находится в регистре AX:

Переполнения и прерывания

Используя команды DIV и особенно IDIV, очень просто вызвать пеpеполнение. Прерывания приводят (по крайней мара в системе, используемой при тестировании этих программ) к непредсказуемым результатам. В операциях деления предполага ется, что частное значительно меньше, чем делимое. Деление на ноль всегда вызывает прерывание. Но деление на 1 генерирует частное, которое равно делимому, что может также легко вызвать прерывание. Рекомендуется использовать следующее правило: если делитель — байт, то его значение должно быть меньше, чем левый байт (AH) делителя: если делитель — слово, то его значение должно быть меньше, чем левое слово (DX) делителя. Проиллюстрируем данное правило для делителя, равного 1:

В обоих случаях частное превышает возможный размер. Для того чтобы избежать подобных ситуаций, полезно вставлять перед командами DIV и IDIV соответствующую проверку. В первом из следующих примеpов предположим, что DIVBYTE — однобайтовый делитель, а делимое находится уже в регистре AX. Во втором примере предположим, что DIVWORD — двухбайтовый делитель, а делимое находится в регистровой паре DX:AX.

Для команды IDIV данная логика должна учитывать тот факт, что либо делимое, либо делитель могут быть отрицательными, а так как сравниваются абсолютные значения, то необходимо использовать команду NEG для временного перевода отрицательного значения в положительное.

Деление вычитанием

Если частное слишком велико, то деление можно выполнить с помощью циклического вычитания. Метод заключается в том, что делитель вычитается из делимого и в этом же цикле частное увеличивается на 1. Вычитание продолжается, пока делимое остается больше делителя. В cледующем примере, делитель находится в регистре AX, а делимое — в BX, частное вырабатывается в CX:

В конце подпрограммы регистр CX будет содержать частное, а AX — oстаток. Пример умышленно примитивен для демонстрации данной техники деления. Если частное получается в регистро вой паре DX:AX, то необходимо сделать два дополнения:

Примечание: очень большое частное и малый делитель могут вызвать тысячи циклов.

Преобразование знака

Команда NEG обеспечивает преобразование знака двоичных чисел из положительного в отрицательное и наоборот. Практически команда NEG устанавливает противоположные значения битов и прибавляет 1. Примеры:

Преобразование знака для 35-битового (или большего) числа включает больше шагов. Предположим, что регистровая пара DX:AX содержит 32-битовое двоичное число. Так как команда NEG не может обрабатывать два регистра одновременно, то ее использование приведет к неправильному результату. В следую щем примере показано использование команды NOT:

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

Математические сопроцессоры (описание)

Системная плата компьютера содержит пустое гнездо, зарезервированное для числового процессора Intel 8087 (или 80287). Сопроцессор 8087 действует совместно с 8088, а сопро цессор 80287 действует совместно с 80286. Каждый сопроцессор имеет собственный набор команд и средства для операций с плавающей запятой для выполнения экспоненциальных, логарифмических и тригонометрических функций. Сопроцессор содержит восемь 80-битовых регистров с плавающей запятой, которые могут представить числовые значения до 10 в 400 сте пени. Математические вычисления в сопроцессоре выполняются примерно в 100 раз быстрее, чем в основном процессоре. Основной процессор выполняет специальные операции и передает числовые данные в сопроцессор, который выполняет необходимые вычисления и возвращает результат. Для ассембли рования с помощью транслятора MASM, необходимо добавлять параметр /E или /R, например, MASM /R.

Как сложить 2 двоичных числа в ассемблере

На этом шаге мы познакомимся с правилами выполнения действий с двоичными числами.

Так как компьютер может различить только нулевое и единичное состояние бита, то он работает в системе счисления с основанием 2 или в двоичной системе . Бит получил свое название от английского Binary digit ( двоичная цифра ) .

Сочетанием двоичных цифр (битов) можно представить любое значение. Значение двоичного числа определяется относительной позицией каждого бита и наличием единичных битов. Ниже показано восьмибитовое число, содержащее все единичные биты:

Самая правая цифра имеет весовое значение 1, следующая цифра влево — 2, следующая — 4 и т.д. Общая сумма для восьми единичных битов в данном случае составит 255 (1+2+4+8+16+32+64+128=255).

Компьютер выполняет арифметические действия только в двоичном формате. Поэтому, программируя на языке Ассемблер, необходимо знать правила сложения в двоичной системе счисления. Напомним их:

Проиллюстрируем использование этих правил на конкретном примере.

Пример: сложить числа 65 и 42, представленные в двоичной системе счисления. В десятичной системе счисления все осуществляется достаточно просто: 65+42=107.

Для сложения этих чисел в двоичной системе счисления нужно сначала перевести их в эту систему:

Рис.1. Алгоритм перевода числа из десятичной в двоичную систему счисления

Таким образом, получаем: 65 10 = 01000001 2 . Обратите внимание на то, что ведущий ноль в двоичном представлении числа добавлен для дополнения двоичного представления до восьми бит.

Аналогично: 42 10 = 00101010 2 . Выполним сложение этих чисел:

Можно убедиться, что 01101011 2 =107 10 :

Мы рассмотрели сложение чисел в компьютере. А как же осуществляется вычитание? Для выполнения операции вычитания оно заменяется сложением, а в качестве второго слогаемого берется противоположное число. Например, пусть надо выполнить вычитание: 65 — 42. Заменим его сложением: 65 + (-42). Но как получить соответствующее двоичное отрицательное число? Этот вопрос мы сейчас рассмотрим.

  • взять соответствующее положительное число и инвертировать его биты (1 заменить на 0 и наоборот);
  • к полученному числу прибавить 1.

Приведем пример использования рассмотренного алгоритма.

Пример 1. Получить двоичное представление числа -65. Напомним, что 65 10 = 01000001 2 . Инвертируем биты: 10111110 . К полученному числу прибавим 1: 10111110+1=10111111 . Убедимся в правильности представления. Сумма +65 и -65 должна составить нуль:

Все восемь бит имеют нулевое значение. Пока будем считать, что полученная единица, перенесенная влево, потеряна.

Это правило позволяет выполнять вычитание чисел в двоичной системе счисления: вычитание заменяется сложением и в качестве второго слагаемого берется отрицательное число.

Пример 2. Вычесть из 65 число 42. Двоичное представление для 42 — это 00101010, а для -42 двоичное представление будет следующим — 11010110:

Пример 3. Какое значение необходимо прибавить к двоичному числу 00000001, чтобы получить число 00000000? В терминах десятичного счисления ответом будет число -1. Для двоичного счисления это число 11111111:

В заключение приведем фрагмент уменьшающегося ряда чисел в двоичном представлении:

На следующем шаге мы познакомимся с шестнадцатеричным представлением чисел.

Похожие статьи