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
           *   *   *





Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Реклама - Реклама и объявления.
Смех сквозь слезы - Компьютерный идиотизм.
Система - Обзор системных программ: копировщик Master Fast Track Copyer v 2. 2

В этот день...   26 сентября