ТОР 5 статей: Методические подходы к анализу финансового состояния предприятия Проблема периодизации русской литературы ХХ века. Краткая характеристика второй половины ХХ века Характеристика шлифовальных кругов и ее маркировка Служебные части речи. Предлог. Союз. Частицы КАТЕГОРИИ:
|
Над двоично-десятичными числамиОпределение и формат BCD-чисел были рассмотрены в начале этого урока. У вас справедливо может возникнуть вопрос: а зачем нужны BCD-числа? Ответ может быть следующим: BCD-числа нужны в деловых приложениях, то есть там, где числа должны быть большими и точными. Как мы уже убедились на примере двоичных чисел, операции с такими числами довольно проблематичны для языка ассемблера. К недостаткам использования двоичных чисел можно отнести следующие: - О значения величин в формате слова и двойного слова имеют ограниченный диапазон. Если программа предназначена для работы в области финансов, то ограничение суммы в рублях величиной 65 536 (для слова) или даже 4 294 9G7 296 (для двойного слова) будет существенно сужать сферу ее применения (да еще в наших экономических условиях — тут уж никакая деноминация не поможет); - О наличие ошибок округления, Представляете себе программу, работающую где-нибудь в банке, которая не учитывает величину остатка при действиях с целыми двоичными числами и оперирует при этом миллиардами. Не хотелось бы быть автором такой программы. Применение чисел с плавающей точкой не спасет — там существует та же проблема округления; - О представление большого объема результатов в символьном виде (ASCII-коде). Деловые программы не просто выполняют вычисления; одной из целей их использования является оперативная выдача информации пользователю. Для этого, естественно, информация должна быть представлена в символьном виде. Перевод чисел из двоичного кода is ASCII-код, как мы уже видели, требует определенных вычислительных затрат. Число с плавающей точкой • еще труднее перевести в символьный вид, А вот если посмотреть на шШестнад-, цатеричное представление неупакованной десятичной цифры (в начале нашего урока) и на соответствующий ей символ в таблице ASCII, то видно, что они ' • отличаются на величину 30hЗОН. Таким образом, преобразование в символьный - вид и обратно получается намного проще и быстрее. Наверняка вы уа<;е убедились в важности овладения хотя бы основами действий с десятичными числами. Далее рассмотрим особенности выполнения основных арифметических операций с десятичными числами. Для предупреждения возможных вопросов отметим сразу тот факт, что Отдельных команд сложения, вычита-__________________________-1П| ния, умножения и деления BCD-чисел нет. Сделано это по вполне понятньцц причинам: размерность таких чисел может быть сколь угодно большой. Склады-ивать и вычитать можно двоично-десятичгшные числа как в упакованном формате так и в неупакованном, а вот делить и умножать можно только неупакованные BCD-числа., Почему это так, будет видно из дальнейшего обсуждения.
1. Неупакованные BCD-числа | - т 1.1. Сложение ^v*!.:;;*'>•;V>:'-•;-••!' ^.r^V;.,,. Рассмотрим два случая сложения. \^ • f;,;,•, '• -ч^-'-- чЧ ->•;(••..?.,;-,";• ^,; •.•• ' !i r!»i-.,i * !i;S •, '', i •('",: ',•-"• г\ ';;.•* /'••.'.; Пример 8.9. Результат сложения не больше 9. 6 = 0000 0110ооооопо -,-...',,:•,•,..,.,•<.!..•''.'"';'.-,.',-'.-.-: ••-.:•,-:- '-/.и.' ' 1
+ •,••,,,-. -••• -.. '.'С'.'-;,'';.';,'...;:;........; 3=- 0000 ООН0011;.;,,,.-,...:. -.•,.... •...,,..... = 9-=0000 1001 100! • "' '; ',',-. ' :..',,;'.'",',-•.- •;'„:;•..; '>;.;.!'•'... Переноса из младшей тетрады в старшую нет. Результат правильный. Пример 8.10. Результат сложения больше 9 ' ;. '. ' '"''•' ' ' '. 6 = 0000 0110 + 06 = 0000 ОНО. •...л: '. •-•>;„. ••-,.:•-';>.• 'Ч/' • ' •.•'•/''•••. • - 07 = 0000 0111;,,;; •.•.-*•.*....;;..•...V:-^-:-,'''•.-...•• '„ „г,.-..,: '-,.,•#•„•. '• = 13=0000 1101 кз-оооо hoi;;: V. '' '•''"' ' "" : •' ' ^ То есть мы получили уже не BCD-число. Результат неправильный. Правильный :>| ааа (ASCII Adjust for Addition) — коррекция результата сложения для Щ Эта команда не имеет операндов. Она работает неявно только с регистром al и Щ анализирует значение его младшей тетрады. Если это значение меньше 9, то флаг | cf сбрасывается в 0, и осуществляется переход к следующей команде. Если это | значение больше 9, то выполняются следующие действия: 1 - г\ к содержимому младшей тетрады al (но не к содержимому всего регистра!) прибавляется 6, тем самым значение десятичного результата корректируется в правильную сторону; - О флаг cf устанавливается в 1, тем самым фиксируется перенос в старший разряд для того, чтобы его можно было учесть в последующих действиях. Так, в примере 8.10, предполагая, что значение суммы 0000 1101 находится в al, после команды ааа в регистре будет 1101 + 0110= 0011, то есть двоичное 0000 ООН0011 или десятичное 3, а флаг cf установится в 1, то есть перенос запомнился в микропроцессоре. Далее программисту нужно будет использовать команду сложения adc, которая учтет перенос из предыдущего разряда. Приведем пример программы сложения двух неупакованных BCD-чисел. Листинг 8.8. Сложение неупакованных BCD-чисел <l>;prg_8_8.asm <2>... •• '-' •'"•'•'" •"•'!:-!'"'"' <3>.data <4> Tlen equ 2;разрядность числа, •.;/ <5> b db 1,7;неупакованное число 71 '••-"••.'.;•••••, •-.-.-.•£• <6> с db 4,5;неупакованное число 54.. • ~ <7> sum db 3 dup (0) •, <8>.code., <9> mmain:;точка входа в программу <10>...,,_.- -(' ' <11> хогr bx,.bx.. t" '. <12> mov cx,.len ' '' • ' ''','' ''' '•'- ''' '. ' <п> mi1: ' •'" ""• ••' • • ••::" :; "••;'.'•,'•• ' <14> mov al,b[bx] • • :' •'- ' -'•'*•' • -' ' •.--."' <15> adc a1.,c[bx] " •• ; '' •': •'/ ''- • / •'• ^ ''-' l^-' ' '--'' <16> aaa. '• • •' •.' '•••' ""• " •••' '••••• • "••', " <17> mov sum[bx],al •.: - •• •'•i!. • •••.•• • -. - •''" '• <18> inc bx..'.-.... '.' •:• •• •>••<•;:•.-... <19> loop ml <20> adc sum[bx].,0 • • • '.•..•• <;1, :- <21>... '..-.-..;.',:'.•- В листинге 8.8 есть несколько интересных моментов, над которыми есть смысл поразмыслить. Начнем с описания BCD-чисел. Из строк 5 и 6 видно, что Порядок их ввода BCD-чисел обратен нормальному, то есть цифры младших разрядов расположены по меньшему адресу. Но это вполне логично по нескольким причинам: во-пер-вых, такой порядок удовлетворяет общему принципу представления данных для микропроцессоров Intel, во-вторых, это очень удобно для поразрядной обработки неупакованных BCD-чисел, так как каждое из них занимает один байт. Хотя, повторюсь, программист сам волен выбирать способ описания BCD-чисел в сегменте данных. Строки 14-15 содержат команды, которые складывают цифры в очередных разрядах BCD-чисел, при этом учитывается возможный перенос из младшего разряда. Команда ааа в строке 16 корректирует результат сложения, формируя в al BCD-цифру и, при необходимости, устанавливая в 1 флаг cf. Стро-_________________________________^——;-^г1Ды ка 20 учитывает возможность переноса при сложении цифр из самых старшихщцх , описанном в стро
Вычитание Ш па s Ситуация здесь вполне аналогична сложению. Рассмотрим те'же'случаи. ™Ц ' • •.:.. v.,• Пример 8.11. Результат вычитания не больше 9е 9 •, • •,;}>;• j 6 = 0000 0110 ••• •. ; -.• :.$ –-'••• • "••',-•. ^
3 = 0000 0011 - ! ' ' : •"'". j 3 = 0000 0011 ' ••'•••' •, " •" '•• •'; - '•! Как видим, Ззаема из старшей тетрады нет. Результат верный и корректировки не \ "i 6 = 0000 0110 – ••-."...••,• ' •?•> • Ш'\ 7 -= 0000 0111 • *Ь. "Я j
= -1 = 1111 1П111 1
Вычитание проводится по правилам двоичной арифметики. Поэтому результат не Таким образом, видно, что, как и в случае сложения, результат вычитания нужно aas (ASCII Adjust for Substraction) — коррекция результата вычитания для представления в символьном виде. Команда aas также не имеет операндов и работает с регистром al, анализируя его младшую тетраду следующим образом: если ее значение меньше 9, то флаг cf сбрасывается в 0, и управление передается следующей команде. Если значение тетрады в al больше 9, то команда aas выполняет следующие действия: - О из содержимого младшей тетрады регистра аl] (заметьте — не из содержимого всего регистра) вычитает 6; - О обнуляет старшую тетраду регистра al; - О устанавливает флаг cf в 1, тем самым фиксируя воображаемый заем из старшего разряда. Понятно, что команда aas применяется вместе с основными командами вычитания sub и sbb. При этом команду sub есть смысл использовать только один раз при вычитании самых младших цифр операндов, далее должна применяться команда sbb hb которая будет учитывать возможный заем из старшего разряда. В листинге 8.9 Листинг 8.9. Вычитание неупакованных BCD-чисел <\>;prg_8_9.asm ", •..:.- •'..?it <ф, masm .ф, model small ф. stack 256 -Jк •-,*..^;С". ^.data;сегмент данных t..,,,. <6> ьb db 1,7;неупакованное число 71 ',. '' <-}> с db 4,5;неупакованное число 54 ' ••"-."•'"• <8> subs db 2 dup (0) - " ' ;"fi- <9>. code : '•' ' " ' ""' ;: <10> main:;точка входа в программу Vl •-..-<• •:,'.„ <ц> rmnov ax,@.^data связываем регистр dx с сегнентйн-•'"• i! •'' <12> mov ds,.ax;данных через регистр ах <13> хогr ах,ах..;очищаем ах.., •. <14> len equ 2;2.' -.разрядность чисел ' ',:•;,;.,'.' <15> хогr bx.,bx,.., |,,,,.., ( <16> mov ecx,len;загрузка в сх счетчика цикла../.'."., <17> ml: '' ; '; '"' : '• <18> mov al,b[bx]. •, '•' "V <19> sbb al.,c[bx].,... ii.jK. ', <20> aas ' ' • ••.'"• •'' " •;41 '-' <21> mov subs[bx],al - "-'• '• • •;..••• • s'"'1 v т; s... <22> •.. Iinc bx..., (|,. ;,:.... '.':- <23> ' loop ml....-- - •. •. <:24> jc m2; анализ флага эзаенма <25> jmp exit = - - '." • ^'-iv:.;:•(-. r~. v • m^26> ni2:.... ".. • •- •=27> exit: <28> mov ax,4c00OOh;стандартный выход ^29> innt 21h.- -.I..',.W- '. ":30> end main;конец программы,; • -,,.,v • Данная программа не требует особых пояснений, когда уменьшаемое больше вычитаемого. Поэтому обратите внимание на строку 24. С ее помощью Мы предусматриваем случай, когда после вычитания старших цифр чисел был зафиксирован факт заема. Это говорит о том, что вычитаемое было больше уменьшаемого, в результате чего разность будет неправильной. Эту ситуацию нужно как-то обработать. С этой целью в строке 24 командой jc анализируется флаг cf. По результату этого анализа мы уходим на ветку программы, обозначенную меткой т2, где и будут выполняться некоторые действия. Набор этих действий сильно зависит от конкретного алгоритма обработки, поэтому поясним только суть действий, которые может Выполнять соответствующий фрагмент программы. Для этого посмотрим в отлад-ике, как наша программа выполнит вычитание 50 - 74 (правильный ответ -24). о, что вы увидите в окне Dump отладчика, в поле, соответствующем адресу subs, УДет далеко от истинного ответа. Что делает в этом случае человек? Он просто ыполняет вычитание 74 - 50 = 24 и рассматривает результат как имеющий знакминус. Так как у микропроцессора нет средств обработки подобной ситуации, то фрагмент программы, обозначенный меткой т2, может поменять уменьшаемое ц вычитаемое местами, выполнить вычитание и где-то отметить тот факт, что раз-ность, на самом деле, нужно рассматривать как отрицательное число. Но ключевой момент здесь все-таки тот, что микропроцессор с помощью флага cf сигнализирует нам об этой особой ситуации.
Умножение I На примере сложения и вычитания неупакованных чисел стаао понятно, что стандартных алгоритмов для выполнения этих действий над BCD-числами нет, и программист должен сам, исходя из требований к своей программе, реализовать эти операции. Реализация двух оставшихся операций — умножения и деления — еще более сложна. В системе команд микропроцессора присутствуют только средства для производства умножения и деления одноразрядных неупакованных BCD-чисел. Для того чтобы умножать числа произвольной размерности, нужно реализовать процесс умножения самостоятельно, взяв за основу некоторый алгоритм умножения, например «в столбик*. Позже мы рассмотрим пример программы, выполняющей умножение десятичных чисел произвольной размерности. Для того чтобы перемножить два одноразрядных BCD-числа, необходимо: - О поместить один из сомножителей в регистр аl (как того требует команда mul); - О поместить второй операнд в регистр или память, отведя байт; - О перемножить сомножители командой mul (результат, как и положено, будет в ах); - О результат, конечно, получится в двоичном коде, поэтому его нужно скорректировать. Для коррекции результата после умножения применяется специальная команда aam (ASCII Adjust for Multiplication) — коррекция результата умножения для представления в символьном виде. Она не имеет операндов и работает с регистром ах следующим образом: - О делит al на 10; - О результат деления записывается так; частное — в al, остаток — в ah. В результате после выполнения команды aam в регистрах al и ah находятся правильные двоично-десятичные цифры произведения двух цифр. В листинге 8.10 приведен пример умножения BCD-числа произвольной размерности на однозначное BCD-число. Листинг 8.10. Умножений неупакованных BCD-чисел ;prg8_10.asm masm model small stack 256 .data b db 6,7;неупакованное число 76 c db 4;неупакованное число 4 proizv db 4 dup (0) .code main:;точка входа в программу mov ax,@data mov ds,ax xor ax,ax len equ 2;размерность сомножителя 1 xor bx,bx xor si,si xor di,di mov cx,len;в cx длина наибольшего сомножителя 1 m1: mov al,b[si] mul c aam;коррекция умножения adc al,dl;учли предыдущий перенос aaa;скорректировали результат сложения с переносом mov dl,ah; запомнили перенос mov proizv[bx],al inc si inc bx loop m1 mov proizv[bx],dl;учли последний перенос exit: mov ax,4c00h int 21h end main
Данную программу можно легко модифицировать для умножения BCD-чисел произвольной длины. Для этого достаточно представить алгоритм умножения в «столбик». Листинг 8.10 можно использовать для получения частичных произведений в этом алгоритме. После их сложения со сдвигом получится искомый результат. Попробуйте выполнить разработку этой программы самостоятельно. Перед окончанием обсуждения Командуы aam необходимо отметить еще один вариант ее применения. Эту команду можно применять для преобразования двоичного числа в регистре al в неупакованное BCD-число, которое будет размещено в регистре ах: старшая цифра результата — в ah, младшая — в al. Понятно, что Двоичное число должно быть в диапазоне 0...99.
1.4. Делениее: Процесс выполнения операции деления двух неупакованных BCD-чисел несколько отличается от других, рассмотренных ранее, операций с ними. Здесь также требуются действия по коррекции, но они должны выполняться до основной операции, выполняющей непосредственно деление одного BCD-числа на другое BCD-число. Предварительно в регистре ах нужно получить две неупакованные BCD-цифры делимого. Это делает программист удобным для него способом. Далее нужно выдать команду aad: aad (ASCII Adjust, for Division) — коррекция деления для представления в символьном виде.
Команда не имеет операндов и преобразует двузначное неупакованное BCD-число в регистре ах в двоичное число. Это двоичное число впоследствии будет играть роль делимого в операции деления. Кроме преобразования, команда aad помещает полученное двоичное число в регистр al. Делимое, естественно, будет двоичным числом из диапазона 0...99. Алгоритм, по которому команда aad осуществляет это преобразование, состоит в следующем: - О умножить старшую цифру исходного BCD-числа в ах (содержимое ah) на 10; - О выполнить сложение ah + al, результат которого (двоичное число) занести в al; - О обнулить содержимое ah. Далее программисту нужно выдать обычную команду деления div для выполнения деления содержимого ах на одну BCD-цифру, находящуюся и байтовом регистре или байтовой ячейке памяти. Деление неупакованных BCD-чисел иллюстрируется листингом 8.11. Листинг 8.11. Деление неупакованных BCD-чисел ;prg8_11.asm masm model small stack 256 .data;сегмент данных b db 1,7;неупакованное BCD-число 71 c db 4; ch db 2 dup (0) .code;сегмент кода main:;точка входа в программу mov ax,@data mov ds,ax xor ax,ax mov al,b aad;коррекция перед делением div c;в al BCD-частное, в ah BCD-остаток ;... exit: mov ax,4c00h int 21h end main Аналогично ааmт, команде aad можно найти и другое применение — использовать ее для перевода неупакованных BCD-чисел из диапазона 0...99 в их двоичный эквивалент.
Для деления чисел большей разрядности, так же, как и в случае умножения, нужно реализовывать свой алгоритм, например в «столбик», либо найти более оптимальный путь. Любопытный и настойчивый читатель, возможно, самостоятельно разработает эти программы. Но это делать совсем необязательно. На дискете, прилагаемой к книге, в каталоге данного урока приведены тексты макрокоманд, которые выполняют четыре основных арифметических действия с BCD-числами любой разрядности.
Не нашли, что искали? Воспользуйтесь поиском:
|