Арифметические команды и команды сравнения

{toc_noshowall}Перейдем теперь к рассмотрению арифметических операцией и операций сравнения над числами, представленными в десятичной форме. Все команды, реализующие выполнение такого типа операций, имеют формат SS с раздельным указанием длины каждого операнда.

Мнемонические обозначения десятичных команд легко запомнить: они получаются из мнемоник соответствующих двоичных команд добавлением символа Р.

Операция

Мнемоника команд двоичной арифметики

Мнемоника команд десятичной арифметики

Сложение

А

АР

Вычитание

 

S

SP

Умножение

 

М

МР

Деление

 

D

DP

Сравнение

 

С

СР

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

Рассмотрим десятичные команды более подробно.

Команды АР и SP предназначены соответственно для выполнения сложения и вычитания двух десятичных чисел, одно из которых расположено по адресу D1+(B1) и имеет длину L1 байтов, а другое — расположено по адресу D2+(B2) и имеет длину L2 байтов.

АР D1(L1,B1),D2(L2,B2)

Add Packed

D1+ (B1)?(D1+ (B1))L1+ (D2 + (B2))L2

SP D1(L1 ,B1),D2(L2,B2)

Subtract Packed

D1+(B1)?(D1 + (B1))L1— (D2 + (B2))L2

Результат выполнения каждой из команд помещается в поле первого операнда, при этом он выравнивается по правой границе. Само выполнение не оказывает влияния на содержимое второго операнда, за исключением случая, когда области первого и второго операндов перекрываются.

По команде

АР NUM1(3),NUM2(2)

двухбайтовое десятичное число, хранящееся в памяти по адресу NUM2, складывается с трехбайтовым числом, хранящимся по адресу

NUM1. Если сначала

NUM1: 75632С

NUM2: 493С

то результатом выполнения приведенной выше команды будет

NUM1: 76125С

Если начальное содержимое областей NUM1 и NUM2 то же, что и прежде, то выполнение команды

SP NUM1(3),NUM2(2)

даст

NUM1: 75139С

Аналогично пусть

AT: 00368D

ВАТ: 336С

После выполнения команды

АР АТ+1 (2), В АТ+1(1)

получим

AT: 00362D

а после выполнения команды

SP ВАТ(2),АТ(3)

получим

ВАТ: 704С

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

Если результат выполнения десятичного сложения или вычитания не помещается в поле, определенном в качестве первого операнда, фиксируется особый случай десятичного переполнения (ОСА). Например, результат выполнения команды

АР NINE(l), = Р'Г

при

NINE: 9С

равный ЮС, не может быть помещен в однобайтовую область. Отметим, что сказанное, конечно, не означает, что поле первого операнда команды такого типа должно быть достаточным для записи всех результатов, которые могут получиться при выполнении данной команды. Фактически выполнение проходит следующим образом: сначала производится вычисление результата, а затем попытка поместить его в отведенную область. Если попытка удалась, то независимо от реальной длины операнда команда считается удачно выполнившейся. Пусть, например,

N1: 958С

N2: 000004 2С

Выполнение команды

АР N1(2),N2(4)

приведет к фиксации особого случая в данных, в то время как выполнение команды

SP N1(2), N2(4)

не вызовет особого случая. Признаки результата вырабатываются командами АР и SP так же, как и всеми остальными арифметическими командами:

Признак результата

Результат

0

Результат = 0

1

Результат < 0

2

Результат > 0

3

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

По команде МР (УМНОЖЕНИЕ ДЕСЯТИЧНОЕ) вычисляется произведение двух десятичных чисел и результат помещается в память на место первого операнда.

МР D1(L1,B1),D2(L2,B2)

Multiply Packed

D1+(B1)?(D1+(В1))L1X(D2 + (B2)L2

Команда МР может быть успешно выполнена лишь тогда, когда область первого операнда достаточна для записи получившегося произведения. На самом деле к размерам области первого операнда предъявляются более строгие требования: в эту область должен помещаться результат выполнения команды МР, дополненный спереди незначащим нулем. Невыполнение этого условия влечет за собой фиксацию особого случая спецификации при попытке выполнения команды.

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

38D

а второй

430С

Произведение

16340D

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

016340D

Множимое имеет две значащие цифры, множитель — три. Проверка выполнения описанного условия производится до начала непосредственного умножения: множимое спереди дополняется четырьмя незначащими нулями. Первый операнд до начала выполнения умножения должен иметь вид

000038D

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

38D

и

430С

необходимо предварительно иметь первый операнд в виде

0000038D

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

Возвращаясь к нашему примеру, можно видеть, что длина множителя (в байтах) равна двум. Следовательно, множимое должно быть дополнено спереди четырьмя нулями. Фактически мы получили тот же результат, что и раньше, только более простым способом. Если длина второго операнда равна 5 байтам, то, следовательно, необходимо добавить к множимому десять нулей и т. д.

Существует естественное ограничение на длину множителя: эта длина не должна превышать 15. Отметим, что длина множимого, как нетрудно видеть, должна всегда быть больше длины множителя.

Все сказанное говорит о том, что выполнение команды МР обычно требует некоторой специальной подготовки. Предположим, что мы хотим вычислить произведение 5-байтового числа, хранящегося в памяти по адресу NUM1, и 6-байтового числа, хранящегося по адресу NUM2. Ясно, что произведение может не уместиться в NUM1. Для обеспечения возможности нормального выполнения команды МР необходимо каким-то образом дополнить первый операнд спереди двенадцатью нулями. Простейшим способом достижения этой цели является пересылка содержимого NUM1 в область, первые шесть байтов которой уже содержат нули. (В подобных случаях очень полезной оказывается команда ZAP, рассматриваемая в разд. 16.3.1.) Итак, получить требуемое произведение можно, например, с помощью команд

MVC TEMP + 6(5), NUM1

МР ТЕМР(11), NUM2

TEMP DC 11Х'00'

Предположим, что содержимое областей NUM1 и NUM2 первоначально выглядело следующим образом:

NUM1: 1038000 10C

NUM2: 60402000001D

Результатом выполнения приведенных выше команд, помещенным в поле TEMP, будет

TEMP: 006269728204123800010D

По команде DP (ДЕЛЕНИЕ ДЕСЯТИЧНОЕ) производится деление одного десятичного числа (делимого), адрес которого указан на месте первого операнда, на другое (делитель), адрес которого указан на месте второго операнда команды DP. Получившиеся в результате деления частное и остаток записываются в память на место делимого.

DP D1 (L1 ,В 1),D2(L2,B2)

Divide Packed

Вычисляется (D1+(B1))L1?(D2+(B2))L2частное? (D1 +(B1))L1-L2 остаток ? (D1 + (В 1) + L 1 — L2)L2

Остановимся подробнее на том, как производится запись результата в память. Заметим, что длина остатка не может превышать длины делителя. Например, если в качестве делителя выступает число 608С, то остаток от деления не может превышать 607С. Если делитель занимает в памяти L2 байтов, то остаток никак не может занимать больше этого количества. После выполнения деления по команде DP получившийся остаток записывается в последние L2 байтов первого операнда. В первые L1—L2 байтов записывается частное. Десятичную операцию деления, так же как и двоичную, можно охарактеризовать следующей формулой:

делимое = делитель х частное + остаток

Знак остатка совпадает со знаком делимого. Частное положительно, если знаки делимого и делителя совпадают, в противном случае частное отрицательно.

Теперь мы знаем достаточно много для того, чтобы рассмотреть пример. Пусть

DIVIDND: 05703С

DIVISR: 608С

и производится деление первого числа на второе. Частное и остаток равны соответственно

и

231C

Длина делителя равна 2, длина делимого — 3. Остаток помещается в последние L2=2 байта области DIVIDND. Частное помещается в первый (LI—L2=l) байт этой >де области. Итак, при данном содержимом областей DIVIDND и DIVISR выполнение команды

DP DIVIDND(3),DIV1SR(2)

даст

DIVIDND: 9С231С

Аналогично, если

DIVIDND: 000307685D

DIVISR: 007G3C

то результатом выполнения

DP DIVIDND(5),DIVISR(3)

будет

DIVIDND: 403D00196C

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

DP DIVI DND(5), DIVISR+ 1(2)

окажется равным

DIVIDND: 00403D196C

Если по сравнению с делимым делитель достаточно мал, то отведенного места может не хватить для размещения вычисленного частного. Например, если

Р: 37605С

Q: 608С

то частное равно

61С

Если команда

DP P(3),Q(2)

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

Признак результата в процессе выполнения команд МР и DP не меняется.

По команде СР (СРАВНЕНИЕ ДЕСЯТИЧНОЕ) производится вычисление разности двух десятичных чисел, длина каждого из которых указывается отдельно. В соответствии со знаком получившейся разности устанавливается признак результата. Содержимое памяти в процессе выполнения команды не меняется,

СР D1 (LI ,B1),D2(L2,B2)

Compare Packed

Устанавливается значение СС в соответствии со знаком разности (D1 +(B1))L1-(D2 + (B2))L2

Признак результата вырабатывается следующим образом:

 

Признак результата

Условия

0

Первый операнд = второй операнд

1

Первый операнд < второй операнд

2

Первый операнд >второй операнд

3

He встречается

Если операнды команды СР имеют различную длину, то для обеспечения возможности выполнения вычитания более короткий операнд дополняется спереди соответствующим количеством нулей. Например, если

N1: 05683С

N5: 9С

и выполняется команда

СР N1(3),N5(1)

то в качестве реальных операндов выступают

05683С

00009С

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

N1 00005С

N5 9С

то той же самой командой будет выработан признак 1; это же произойдет, если будет выполнена команда

СР МЗ(2),М7(5)

при условии, что

М3: 400D

М7: 000000500D

При выполнении команды СР производится проверка на правильность подготовки исходных данных. Если хотя бы один из операндов не является правильным упакованным десятичным числом, фиксируется особый случай в данных.