Представление чисел в 16- разрядном компьютере
Определим основные области представления чисел в табл. 4.1: 1 – область старших беззнаковых чисел, 2 – область младших беззнаковых чисел или положительных знаковых чисел, 3 – область отрицательных знаковых чисел, 4 – " квази-область" положительных чисел. Пользоваться этой формой задания чисел, допускаемой ассемблером, не рекомендуется. В заключение отметим, что знак числа условен. Одно и то же число 0FFFFh может рассматриваться как максимальное число, а в другом – как отрицательное число –1, представленное в дополнительном коде. Таким образом, знак числа является характеристикой не самого числа, а способа его обработки. 9.2.2. Преобразование ASCII-кодов чисел с произвольным основанием Задания к лабораторной работе предусматривают использование чисел с различным основанием (2, 8, 10 и 16), поэтому здесь рассматривается способ, не зависящий от основания системы счисления. Преобразование числовых ASCII -строк в двоичное число обычно реализуется в два этапа. На первом этапе каждая ASCII- цифра (байт) преобразуется в неупакованный формат со старшей нулевой тетрадой, а затем, на втором этапе, цепочка неупакованных байтов преобразуется в число по правилу Горнера. Наиболее просто реализуется первый этап для чисел с основанием P, равным 2, 8, и 10, и несколько усложняется для основания P = 16. Из табл. 4.2 следует, что в последнем случае при переходе от ASCII- кода цифры к двоичному коду цифры (младшая тетрада) необходимо предварительно выполнить операцию сравнения на принадлежность ASCII- кода к цифре или прописной букве (A, B,...F). В первом случае выполняется операция вычитания с числом 30h, а во втором – с числом 37h. Таблица 4.2 Таблица ASCII- кодов цифр
Реализацию схемы Горнера на втором этапе для n-разрядного числа А = anan-1...a1 с основанием Р можно представить в следующем виде: anan-1...a2a1=((...(0 * P + an)P + an-1)P +...+a2)P + a1. Преобразование начинается с самой старшей цифры числа и состоит из n циклов, каждый из которых использует две операции: умножение на основание системы счисления P промежуточного результата (первый промежуточный результат равен 0) с последующим прибавлением к нему двоичного кода (байта) следующей младшей цифры преобразуемого числа. Пример преобразования десятичного числа: 237(10) = 11101101(2). Рассмотренный алгоритм преобразования десятичного ASCII- числа в двоичное число реализован в программе, представленной в листинге 4.1. Листинг 4.1. Преобразовать знаковое десятичное ASCII- число из буфера (6 байт = знак + 5 цифровых разрядов) по адресу в bx в 16-разрядное двоичный код в регистре ax. Comment /* Вход: Знаковое десятичное ASCII-число в буфере байтового типа с начальным адресом в BX, CX -количество ASCII-символов числа, включая знак '-'. Расположение числа в буфере: в первом байте буфера располагается старший цифровой разряд положительного числа или знак " минус" отрицательного. Выход: ax -16-разрядное двоичный код в регистре ax, Флаг cf=1, если преобразуемое число больше 32767 или меньше -32768, иначе cf=0. */ proc #dec_bin cmp [byte bx], '-'; Отрицательное число? jne positive inc bx; Продвинем указатель и dec cx; уменьшим счётчик цикла call conv; Преобразуем модуль отрицательного десятичного числа. ; На выходе: ax – двоичный код, ; сf=1, если преобразуемое число превышает значение 65535 (т.е. регистр ax переполнится в процессе преобразования) jc overflow; Число > 65535? cmp ax, 32768 ja overflow; Число > 32768 neg ax; Сформируем дополнительный код js good; Закончим преобразование positive: call conv; Преобразуем модуль положительного десятичного числа. jc overflow; Число > 65535? cmp ax, 32767 jbe good; Число< 32767 overflow: stc; cf=1 jmp n_good; Выйдем из преобразования good: clc; cf=0 n_good: ret endp #dec_bin proc conv; push dx di xor ax, ax; Очистим регистр двоичного числа mov di, 10; 10- основание системы счисления cycl: mul di; dx: ax = ax*10 jc over_flow; Переход, если CF=1 mov dl, [bx]; Выберем очередную ASCII-цифру sub dl, 30h; Образуем двоичное число add ax, dx; Промежуточная сумма jc over_flow; Переход, если CF=1 inc bx loop cycl; Продолжим, если cx> 0 clc; Нет, сбросим флаг CF=1 over_flow: pop di dx ret endp conv 9.2.3. Преобразование двоичного числа в ASCII-строку числа Данное преобразование представляет собой процесс обратный предыдущему. На первом этапе происходит формирование младших двоичных тетрад для соответствующих ASCII -цифр (символов), на втором – получение собственно ASCII -кодов. Первый этап реализуется путём последовательного использования операции деления исходного двоичного числа и его частных на основание соответствующей системы счисления P. Полученные остатки и представляют собой двоичные тетрады соответствующих байтов ASCII- кодов (первый остаток определяет младшую цифру преобразуемого числа, последний – старшую). Цикл деления, в котором формируется нулевое значение частного, означает конец преобразования. Второй этап преобразования сводится к выполнению операции сложения полученных остатков с числом 30h (Р = 2, 8, 10 и, выборочно, для формирования ASCII- кодов младших цифр 16-теричного числа). Для формирования ASCII -символов A, B,..., F используется число 37h. Чтобы не заниматься хранением промежуточных результатов первых этапов, рекомендуется в каждом цикле преобразования объединять оба этапа (прямого или обратного). Пример преобразования двоичного числа в десятичное: 11101101(2)=237(10). Рассмотренный алгоритм преобразования двоичного числа в десятичное ASCII -число реализован в программе, представленной в листинге 4.2. Листинг 4.2. Подпрограмма преобразования 16-битового двоичного дополнительного кода из регистра ах в десятичное ASCII -число со знаком в буфере dec_buf (знак+5цифр). Адрес буфера находится в регистре bx. Comment /* Вход: ax – 16-битовый двоичный дополнительный код, bx – адрес буфера dec_buf десятичного ASCII- числа размером 6 байт. Выход: десятичное ASCII- число в буфере dec_buf (знак+5цифр), ax – сохраненный двоичный дополнительный код. Дополнительные условия: младший разряд десятичного ASCII -числа должен располагаться в последнем, старшем по адресу, байте буфера.*/ Proc Bin_#dec push dx di cx push ax; Сохраним знак преобразуемого числа mov cx, 6; Размер буфера в байтах Blank: mov [byte bx], ' '; Очистим буфер, т.е. заполним его пробелами inc bx loop Blank dec bx; Установим адрес последнего элемента буфера mov di, 10; Введём основание десятичной системы счисления or ax, ax; Установим флаг знака SF jns trans; Перейдём к преобразованию, если SF=0 neg ax; Изменим знак trans: sub dx, dx; Сделаем dx=0 div di; ax=quot(dx: ax/10), dx=rem(dx: ax/10) add dl, '0'; Сформируем десятичную ASCII-цифру mov [byte bx], dl; Занесём в буфер dec bx; Движение назад or ax, ax; Преобразование закончено? jnz trans; Повторить, если АХ> 0 pop ax; Восстановить исходное число, or ax, ax; с целью определения его знака jns out_ trans; Выходим из подпрограммы, если SF=0 mov [byte bx], '-'; Запишем знак '-' для отрицательного числа pop cx di dx out_trans: ret Endp Bin_#dec End
|