ZX Review #7-8-9-10
08 ноября 1997

Читатель-читателю - Печать чисел в различных системах счисления.

<b>Читатель-читателю</b> - Печать чисел в различных системах счисления.
(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
           *   *   *




Другие статьи номера:

TR-DOS для начинающих - Окончание.

Компьютерная новелла - Prince of Persia.

Компьютерная новелла - Лазерная бригада (по игре Laser Squad).

Перекресток драконов - Игра Rapscallion.

Перекресток драконов - Игра The Runes of Zendos.

Перекресток драконов - Игра The Saga.

Перекресток драконов - Игра Witch's Cauldron.

Перекресток драконов - Создаём Адвентюру. Обзор редакторов.

Перекресток драконов - Создаём словарь к Адвентюрной игре.

Программы, которые мы выбираем - Возможные последствия использования недокументированных команд.

Программы, которые мы выбираем - О замеченных шероховатостях в работе некоторых программ и пожелания к следующим версиям.

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

Программы, которые мы выбираем - Несколько предложений по усовершенствованию ассемблера.

Программы, которые мы выбираем - Предложения по доработке ZX Word v2.5.

Программы, которые мы выбираем - Программа "Эмулятор Спектрума" v1.2.

Программы, которые мы выбираем - Что хотелось бы иметь в идеальном ассемблере.

Ретро - 40 лучших процедур: Копирование данных в памяти.

Ретро - 40 лучших процедур: Обмен токена.

Ретро - 40 лучших процедур: Определение адреса БЕЙСИК-строки.

Ретро - 40 лучших процедур: Определение длины БЕЙСИК-программы.

Ретро - 40 лучших процедур: Определение размера свободной памяти.

Ретро - 40 лучших процедур: Поиск и замещение строки.

Ретро - 40 лучших процедур: Поиск подстроки.

Ретро - 40 лучших процедур: Поиск строки.

Ретро - 40 лучших процедур: Составление списка переменных.

Ретро - 40 лучших процедур: увеличение и копирование экрана.

Ретро - 40 лучших процедур: Удаление REM-строк.

Ретро - 40 лучших процедур: Удаление блока программы.

Советы экспертов - Игра Fredloader.

Советы экспертов - Игра Robin of Sherwood: The Touchstones of Rhianon.

Советы экспертов - Игра Scorpions: Die Machines.

Советы экспертов - Игра Terropods.

Страничка iS-DOS - Описание рестартов системы IS DOS.

Форум - Алгоритм распознавания символов.

Форум - Время выполнения недокументированных команд процессора Z80.

Форум - Концепция экрана высокого цветового разрешения.

Форум - Несколько Pokes к играм. Программа Hacman96.

Форум - По поводу новых DOS и BIOS для Спектрума.

Форум - Программа Multicolor на любой модели компьютера. Использование 2-го экрана для Multicolor'а. Демонстрация текста. Электронные журналы.

Форум - Проект ZX Config.

Форум - Усовершенствование Art Studio. Идеи относительно компрессии файлов.

Форум - Эмулятор ZX Spectrum на IBM. По поводу шестнадцатеричной системы счисления. Программа ZX-Stars. Странности в Elita

Форум - Эффекты на бордюре и Multicolor.

Читатель-читателю - ZX Spectrum 128 - новые возможности, новые проблемы.

Читатель-читателю - Группа 'Light'. Спектрум и экспертная система.

Читатель-читателю - Драйвер принтера для Scorpion'а.

Читатель-читателю - Печать чисел в различных системах счисления.

Читатель-читателю - Программирование аркадной игры со скроллингом экрана.

Читатель-читателю - Процедура печати меток ассемблера XAS для монитора-отладчика STS 4.3.

Этюды - Атрибутная бегущая строка. "Гасилка" экрана. Упрощенный вариант процедуры "Занавес". Процедура гащения картинки. Процедура проявления картинки по точкам.

Этюды - Графический эффект "цветные полосы".

Этюды - Драйвер экрана для печати по 64 символа в строке.

Этюды - Комплект защит загрузчиков.

Этюды - Обращение к диску в режиме IM 2. Работа с диском нестандартного формата.

Этюды - Печать символа, увеличенного в 8 раз. Программа "наливания" экрана. Процедура гашения экрана по точкам. Очистка экрана как в Terminator'е. Поиск последовательности символов в памяти. Система перекодировки символьного набора.

Этюды - Программа - каталогизатор дисков.

Этюды - Программа вывода значений амплитуды каналов муз. сопроцессора на бордюр.

Этюды - Программа вывода картинки.

Этюды - Программа зажигания спрайта.

Этюды - Программа очистки заданного окна экрана.

Этюды - Программа сортировки массива по возрастанию. Процедура заполнения экрана заданным атрибутом. Процедура проявления картинки. Эффект летящих навстречу звезд. "Душ", идущий из верхнего левого угла экрана. Процедура "осыпания" картинки по пиксельным линиям. Программа "вытягивания" картинки под углом в 45 градусов. Три процедуры "Scroll".

Этюды - Процедура печати чисел.

Этюды - Процедура прорисовки символа с помощью атрибутов.

Этюды - Процедура проявления картинки. Fade-OUT эффект (картинка уходит за края экрана). Графический эффект "Фонтан". Fade-OUT эффект, имитирующий выключение телевизора. Процедура "зажигания" картинки. Программа плавной прорисовки картинки.

Этюды - Процедура рисования линии.

Этюды - Процедура составления оптимальной таблицы символов.

Этюды - Скроллинг строк текста в заданном окне. Атрибутный скроллер. Диагональный скроллинг.

Этюды - Спрайтовый скроллер. Процедуры проявления экрана.

Этюды - Укороченная процедура индикации амплитуды каналов муз. сопроцессора. Способ вычитания константы из регистровой пары HL.

Этюды - Формула для вычисления дня недели.


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

Похожие статьи:
Хотите Party? - наши комментарии к Music COMpO на СС999.
7 Origins - Семерка лучших origin'ов-мудрых и не очень выражений.
Проба пера - Рассказ "Война продолжается" (продолжение: глава 2,3)
Part 6 - Spectrum quiz II.
Новое в жизни - Новости из Бреста.

В этот день...   19 апреля