ZX Review
#7-8-9-10
08 ноября 1997 |
|
Читатель-читателю - Печать чисел в различных системах счисления.
(c) Колотов Сергей, г.Шадринск, SerzhSoft, V, 1997. ПЕЧАТЬ ЧИСЕЛ В РАЗЛИЧНЫХ СИСТЕМАХ СЧИСЛЕНИЯ Одной из важнейших компьютер- ных задач является вывод чисел на экран (печать). Причем числа могут представляться в различных системах счисления, которых су- ществует не так уж и мало. Наиболее привычной для всех нас, конечно же, является деся- тичная система, т.е. система счисления с основанием 10. Де- сятка здесь фигурирует не слу- чайно: человек с глубокой древ- ности считал с помощью пальцев рук, а их, как известно, - де- сять. Но компьютеру "привычней" считать не в десятичной системе, а в двоичной, т.к. вся информа- ция в нем представляется элек- трическими зарядами: есть ток (1) и нет тока (0). Так как же перевести с "компьютерного" язы- ка на нормальный, человеческий? Следующая процедура выпол- няет печать числа, заданного в регистре A (аккумуляторе) в де- сятичной форме. Печать выпол- няется стандартной командой RST #10 в текущий поток вывода. Дли- на процедуры 23 байта. В своей работе она использует 3-байтную таблицу степеней десятки и, при выполнении, в цикле подсчитыва- ет и распечатывает количество сотен (первая цифра), десятков (вторая) и единиц (третья цифра) числа. см. Listing 1. Но все же маловероятно, что так и не появится необходимость печати, скажем, в шестнадцате- ричной или двоичной системах счисления. Да хотя бы и в той же десятичной, но, например, чисел в диапазоне не от 0 до 255, а от 0 до 65535. Поэтому достаточно целесообразно всегда "иметь под рукой" библиотечку процедур, предназначенных для печати чи- сел в самых различных системах счисления, в самых различных диапазонах. Что мной и реализо- вано... см. Listing 2. В состав данной библиотеки входят процедуры для печати чи- сел в самых различных системах счисления. А именно: десятичная, шестнадцатеричная, двоичная, ус- тановленная пользователем (на- пример, восьмеричная) и, как особо экзотичная, система рим- ских чисел. Процедуры, составляющие биб- лиотеку, имеют много общего, и, полностью разобравшись с одной, можно более быстро вникнуть в принцип работы остальных. Все заголовки процедур печати начи- наются с символа P (Print). Да- лее идут три буквы, определяю- щие систему, в которой распеча- тывается число. Затем, отделяясь символом подчеркивания, следует один из символов B или W, опре- деляя диапазон печатаемого чис- ла: байт (Byte) или слово (Word). В первом случае (B) пе- ред вызовом процедуры число дол- жно находиться в регистре A (ак- кумуляторе), а во втором случае (W) - в регистровой паре HL. Пе- чать производится в текущий по- ток вывода (команда RST #10). Описание библиотеки PDES LIB 1. Печать десятичных чисел 1) Процедура PDEC_W - печать числа, находящегося в ре- гистровой паре HL. Диапа- зон печати: 00000..65535. Длина процедуры 26 байт. Использует таблицу степе- ней десятки DECTB_W. 2) Процедура PDEC_B - печать числа в A (000..255), 10 байт. В своей работе вызы- вает PDEC_W. 3) Таблица DECTB_W - содержит 5 степеней десятки, задан- ных как слова (2 байта) - длина 10 байт. Общая длина раздела: 10+10+26 =46 байт. 2. Печать шестнадцатеричных чисел 1) Пр-ра PHEX_LB - печать мл. полубайта в A (0..F), 14 байт. 2) Пр-ра PHEX_HB - печать ст. полубайта в A (0..F), 4 байта. Меняет местами по- лубайты в A и вызывает PHEX_LB. 3) Пр-ра PHEX_B - печать чис- ла в A (00..FF), 3 байта. Два раза вызывает PHEX_HB. 4) Пр-ра PHEX_W - печать чис- ла в HL (0000..FFFF), 5 байт. Два раза вызывает PHEX_B. Общая длина раздела: 5+3+4+14 =26 байт. 3. Печать двоичных чисел 1) Пр-ра PBIN_B - печать чис- ла в A (8 разрядов), 12 байт. 2) Пр-ра PBIN_W - печать чис- ла в HL (16 разрядов), 5 байт. Два раза вызывает PBIN_B. Общая длина раздела: 5+12=17 байт. 4. Печать чисел в системе счис- ления с основанием, установлен- ным пользователем. Прототипом послужили проце- дуры, опубликованные в отличном справочнике - книге Н.Родионова и А.Ларченко "ZX-Spectrum для пользователей и программистов". 1) Пр-ра MKUSETB - заполнение таблицы степеней USE_TBL с основанием, заданным в ак- кумуляторе. Длина пр-ры 28 байт. 2) Пр-ра PUSE_W - печать чис- ла в HL. Использует ранее созданную MKUSETB таблицу степеней USE_TBL. 33 бай- та. 3) Таблица USE_TBL - таблица степеней, 32 байта. Общая длина раздела: 32+33+28 =93 байта. 5. Печать римских чисел 1) Пр-ра PRIM_W - печать чис- ла в HL (I..MMMCMXCIX), 77 байт. Использует таблицу RIM_TBL. 2) Пр-ра PRIM_B - печать чис- ла в A (I..CCLV). Длина 3 байта. Вызывает процедуру PRIM_W. 3) Таблица RIM_TBL - таблица значимости букв в написа- нии римских чисел. Длина: 7*3=21 байт. Общая длина раздела: 21+3+77 =101 байт. Полный размер библиотеки: 283 байта. 140. Listing 1. Процедура печати байта в десятичной системе. PDEC_B ;Печать десятичного числа в аккумуляторе3 (000..255) LD HL,DECTB_B ;адрес таблицы степеней десятки LD B,#03 ;макс. возможное количество цифр LP_PDB1 LD C,"0"-1 ;инициализация счетчика LP_PDB2 INC C ;увеличиваем счетчик SUB (HL) ;вычитаем текущую степень десятки JR NC,LP_PDB2 ;повторять, пока A>=0 ADD A,(HL) ;A=A mod (HL); C=STR$(A div (HL)) PUSH AF ;сохранить A на стеке LD A,C ;текущая цифра RST #10 ;печать цифры POP AF ;восстановление аккумулятора INC HL ;переход к след. степени десятки DJNZ LP_PDB1 ;закрутили цикл по цифрам RET ;выход из процедуры ; DECTB_B DB 100,10,1 ;Таблица степеней3 10-ки для byte Listing 2. Библиотечка печати в различных системах счисления. ;------ PDES LIB ------ ;Printing in Different Evaluation Systems LIBrary ;(c) SerzhSoft, Shadrinsk, V,3 1997 ; _NULL EQU 0 ;используется в изменяемых командах ; ;--- print in DEC system --- ; PDEC_B ;Печать десятичного числа в A3 (000..255) LD L,A ;поместили LD H,#00 ; число в HL LD DE,DECTB_W+4 ;адрес в таблице, начиная с сотни LD B,#03 ;макс. возможное кол-во цифр - три JR LP_PDW1 ;переход на цикл печати ; PDEC_W ;Печать десятичного числа в HL3 (00000..65535) PUSH HL ;закинули печатаемое число на стек LD HL,DECTB_W ;адрес таблицы степеней десятки LD B,#05 ;макс. возможное количество цифр LP_PDW1 LD E,(HL) ;взяли текущую степень INC HL ; десятки из таблицы LD D,(HL) ; и поместили в DE INC HL ;перешли к след. элементу таблицы EX (SP),HL ;адрес эл-та <-> печатаемое число XOR A ;обнулили счетчик и флаг C для SBC LP_PDW2 INC A ;увеличиваем счетчик SBC HL,DE ;вычитаем текущую степень десятки JR NC,LP_PDW2 ;повторяем пока HL>=0 ADD HL,DE ;HL=HL mod DE; A=HL div DE ADD A,"0"-1 ;перевод A в ASCII-код ("0".."9") RST #10 ;печать десятичной цифры EX (SP),HL ;HL=адрес эл-та, число -> на стек DJNZ LP_PDW1 ;цикл по цифрам POP HL ;убрали оставшийся ноль со стека RET ;выход из процедуры ; DECTB_W DW 10000,1000,100,10,1 ;Таблица степеней десятки ; ;--- print in HEX system --- ; PHEX_W ;Печать шестнадцатеричного числа в HL3 (0000..FFFF) LD A,H ;печать старшего байта числа CALL PHEX_B ;вызов процедуры HEX-печати байта LD A,L ;печать младшего байта числа ; PHEX_B ;Печать шестнадцатеричного числа в A3 (00..FF) CALL PHEX_HB ;печать по полубайтам ; PHEX_HB ;Печать старшего полубайта в A3 (0..F) RRCA ;меняем RRCA ; местами RRCA ; старший RRCA ; и младший полубайты ; PHEX_LB ;Печать младшего полубайта в A3 (0..F) PUSH AF ;сохранили A на стеке AND #0F ;отбросили лишние старшие биты CP #0A ;если A<10, JR C,GO_PHL ; то перепрыгнули ADD A,"A"-"9"-1 ;корректировка: после "9" идет "A" GO_PHL ADD A,"0" ;перевод в ASCII-код RST #10 ;печать HEX-цифры ("0".."F") POP AF ;восстановили A со стека RET ;выход из процедуры ; ;--- print in BIN system --- ; PBIN_W ;Печать двоичного числа в HL (16 разрядов 0/1) LD A,H ;печать старшего байта числа CALL PBIN_B ;вызов процедуры BIN-печати байта LD A,L ;печать младшего байта числа ; PBIN_B ;Печать двоичного числа в A (8 разрядов 0/1) LD B,#08 ;в байте - 8 битов LP_PBB RLCA ;поочередно 'выдвигаем' биты в CF PUSH AF ;сохранить A на стеке LD A,#18 ;в зависимости от флага C: RLA ; A="0" или A="1" RST #10 ;печать очередного бита POP AF ;восстановить A со стека DJNZ LP_PBB ;поразрядный цикл RET ;выход из процедуры ; ;--- print in USER system --- ; PUSE_W ;Печать числа в установленной MKUSETB системе сч-я в HL PUSH HL ;закинули печатаемое число на стек HL_PUW LD HL,_NULL ;адрес конца таблицы степеней LP_PUW1 DEC HL ;загружаем в DE очередную LD D,(HL) ; степень числа DEC HL ; из таблицы, LD E,(HL) ; двигаясь 'сверху-вниз' EX (SP),HL ;адрес таблицы <-> печат-е число XOR A ;обнуление A и сброс флага C LP_PUW2 INC A ;вычисляем очередной SBC HL,DE ; разряд числа и результат JR NC,LP_PUW2 ; помещаем в A (A=1+(HL div DE)) ADD HL,DE ;восстанавливаем (+) значение ADD A,"0"-1 ;переводим A в ASCII-код CP "9"+1 ;если код меньше "9", JR C,GO_PUW1 ; то переход на печать ADD A,"A"-"9"-1 ;коррекция (после "9" идет "A") GO_PUW1 RST #10 ;печать очередной цифры числа EX (SP),HL ;HL=адрес таблицы, число -> стек DEC DE ;если степень LD A,D ; числа не равна единице OR E ; (самый первый элемент таблицы), JR NZ,LP_PUW1 ; то продолжаем работу POP HL ;убираем со стека ненужный 0 RET ;выход из процедуры ; MKUSETB ;Создание таблицы степеней с основанием в A LD HL,USE_TBL ;адрес создаваемой таблицы LD DE,#0001 ;инициализация счетчика степени LP_MUT1 LD (HL),E ;запись текущего INC HL ; значения степени LD (HL),D ; в таблицу и переход INC HL ; к ее следующей ячейке PUSH HL ;сохраняем адрес на стеке LD B,A ;осн-е степени -> в счетчик цикла LD HL,#0000 ;обнуление результата LP_MUT2 ADD HL,DE ;подсчитываем результат JR C,GO_MUT ;если HL>65535, то прерываем счет DJNZ LP_MUT2 ;повторяем <основание> раз EX DE,HL ;результат -> в DE (новая степень) GO_MUT POP HL ;восстанавливаем адрес таблицы JR NC,LP_MUT1 ;если не прерывались, то повторяем LD (HL_PUW+1),HL ;адрес конца таблицы -> в PUSE_W RET ;выход из процедуры ; USE_TBL DS 32 ;Таблица степеней текущей системы счисления ; ;--- print in RIM system --- ; PRIM_B ;Печать числа в римской записи в A (I..CCLV) LD L,A ;скопировать LD H,#00 ; A в HL ; PRIM_W ;Печать числа в римской записи в HL (I..MMMCMXCIX) PUSH HL ;закинули печатаемое число на стек LD HL,RIM_TBL ;адрес таблицы знаков DB #DD ;работаем с половинкой регистра IX LD L,#07 ;LD XL,число знаков в р. счислении LP_PRW1 LD E,(HL) ;считываем из таблицы значение INC HL ; очередного знака римской системы LD D,(HL) ; счисления и помещаем в DE INC HL ;затем в регистр C считываем LD C,(HL) ; ASCII-код знака INC HL ;переход к следующему знаку LD (HL_PRW+1),HL ;сохранили адрес следующего знака EX (SP),HL ;адрес -> на стек, HL=печат. число XOR A ;обнуление счетчика и сброс CF LP_PRW2 INC A ;в цикле производим SBC HL,DE ; деление HL на DE (вычитаем, JR NC,LP_PRW2 ; пока нет переполнения) ADD HL,DE ;восстанавливаем (+) значение DEC A ;т.к. A на 1 больше HL div DE, JR Z,GO_PRW1 ; то если A=1 - ничего не печатаем LD B,A ;количество печатаемых символов LP_PRW3 LD A,C ;код знака RST #10 ;печатаем его DJNZ LP_PRW3 ;сколько надо - столько и печатаем GO_PRW1 DB #DD ;работаем с половинкой регистра IX LD A,L ;LD A,XL - номер текущего знака DEC A ;если это последний знак (I), то JR Z,GO_PRW4 ; двухбуквенного сочетания нет EX (SP),HL ;HL=адрес след. знака, число->стек RRA ;если номер текущего знака четный, JR C,GO_PRW2 ; то сочетание с следующим знаком INC HL ;иначе - перепрыгнуть через один INC HL ; знак. В результате получим адрес INC HL ; знака, для получения двойного GO_PRW2 LD A,C ; знакосочетания (IV,CM,XL...) LD C,(HL) ;взяли из таблицы значение для INC HL ; этого знака и получили LD B,(HL) ; разность между значением INC HL ; основного и этим значением. EX DE,HL ; Например, для основного знака X AND A ; дополнительным будет I, а их SBC HL,BC ; разность соответственно: 140. EX DE,HL ; 10-1=9, т.е. IX LD C,A ;код основного знака LD A,(HL) ;код дополнительного знака EX (SP),HL ;HL=печатаемое число SBC HL,DE ;если оно < дополнительного JR C,GO_PRW3 ; значения, то не печатаем RST #10 ;печать дополнительного знака LD A,C ;основной знак RST #10 ;печать JR GO_PRW4 ;результат - двухбукв. сочетание GO_PRW3 ADD HL,DE ;восстановили (+) у числа GO_PRW4 EX (SP),HL ;число -> на стек HL_PRW LD HL,_NULL ;адрес следующего знака в таблице DB #DD ;работаем с половинкой регистра IX DEC L ;DEC XL - уменьшаем счетчик знаков JR NZ,LP_PRW1 ;крутим цикл, пока есть еще знаки POP HL ;сняли ненужный уже ноль со стека RET ;выход из процедуры ; RIM_TBL ;Таблица значимости букв в написании римских чисел DW 1000 DB "M" ;M=1000 ;CM=900 DW 500 DB "D" ;D=500 ;CD=400 DW 100 DB "C" ;C=100 ;XC=90 DW 50 DB "L" ;L=50 ;XL=40 DW 10 DB "X" ;X=10 ;IX=9 DW 5 DB "V" ;V=5 ;IV=4 DW 1 DB "I" ;I=1 ;-nop- ; ;--- end of PDES LIB --- 2 * * *
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября