Nicron
#33
07 мая 1997 |
|
Программирование - когда калькулятор бейсика противопоказан.
(C) WLODEK BLACK Здравствуйте, друзья. Я снова пришел грузить вас на праздники... Поздравляю всех с Праздником Победы! Продолжаем тему занятия... КОГДА КАЛЬКУЛЯТОР БЕЙСИКА ПРОТИВОПОКАЗАН Встречаются ситуации, когда вычисления, причем достаточно сложные (по сравнению с элементарными действиями типа "сложить" или "вычесть"), проводить с помощью калькулятора Бейсика нецелесообразно или же невозможно (например, когда нельзя вызывать подпрограммы из ПЗУ). Вот как можно распечатать на экране число в десятичном виде в диапазоне #0000-#FFFF: Вход: HL=число DENARY LD DE,10000 ; определяем, сколько раз по 10000 CALL DIGIT LD DE,1000 ; -"- по 1000 CALL DIGIT LD DE,100 ; -"- по 100 CALL DIGIT LD DE,10 ; -"- по 10 CALL DIGIT LD A,L ; остались единицы INC A ; добавляем единицу JR DIGIT2 DIGIT XOR A ; обнуляем счетчик и одновр. сбрасываем флаг C DIGIT1 SBC HL,DE ; вычитаем в цикле до появления заема INC A ; наращиваем счетчик JR NC,DIGIT1 ; цикл до появления заема ADD HL,DE ; восстанавливаем остаток DIGIT2 ADD A,47 ; прибавляем 47 для получ-я кода символа цифры JP PRINT ; печатаем цифру Алгоритм процедуры DENARY прост: последовательно определяя, сколько раз по 10000, по 1000 и т.д. содержится в исходном числе, подсчитываем последовательно цифры всех десятичных разрядов числа и печатаем их. Команда INC A не влияет на флаг переноса, поэтому ее можно использовать после SBC HL,DE. На метке DIGIT2 стоит команда ADD A,47. Почему не 48, ведь код символа цифры = значение цифры + 48 ? Дело в том, что счетчик на регистре A всегда будет делать один лишний оборот, то есть в нем на выходе из подпрограммы DIGIT всегда будет на единицу больше, чем "надо". Вот эту лишнюю единицу мы и компенсируем, прибавляя 47, а не 48. А вот при печати разряда единиц, когда мы берем число единиц прямо из регистра L, не используя подпрограмму DIGIT, лишней единички не возникает, и ее мы сами прибавляем, выполняя INC A. Процедура печати PRINT не должна изменять HL. А вот одно из решений противоположной задачи - получения числа по его записи в виде цифр. В качестве примера я приведу процедуру "CALC" из программы AUTOHISTORIZER-2. В "хистори" сервера каждая строка выглядит аналогично вот этой: 4628902 < NICRON32 B 214 В 22-24 позициях (считая слева от нуля) располагается трехзначное число, показывающее длину файла в секторах. Автохисторизатор в числе прочих имеет функцию подсчета суммы скачанных секторов. Вот как запись числа в виде цифр преобразуется в значение числа: Вход: HL=предыдущее значение суммы; Выход: HL=новое значение суммы: CALC PUSH HL LD IX,(TMPPOI) ; указатель на начало строки LD E,(IX+22) ; цифра сотен LD D,0 LD HL,SUM100-48 ; список сотен со смещением ADD HL,DE LD E,(HL) ; значение сотен POP HL ADD HL,DE ; добавили сотни PUSH HL LD E,(IX+23) ; цифра десятков LD HL,SUM10-48 ; список десятков со смещением ADD HL,DE LD E,(HL) ; значение десятков POP HL ADD HL,DE ; добавили десятки LD A,(IX+24) ; цифра единиц SUB 48 LD E,A ; значение единиц ADD HL,DE ; добавили единицы RET ; готово SUM100 DEFB 0,100,200 SUM10 DEFB 0,10,20,30,40,50,60,70,80,90 Алгоритм построен на использовании списков готовых значений сотен и десятков. По цифре в записи числа определяется нужный элемент списка, считывается значение из списка и прибавляется к общей сумме. Единицы определяются проще - путем вычитания 48 из кода символа цифры. Нетрудно увидеть, что в процедуре CALC нет циклов; время исполнения процедуры не зависит от значения числа. Попробуйте предложить решение подобной задачи для случая, когда в символьной записи числа в разряде сотен может оказаться цифра больше 2 - в этом случае даже 300 уже не поместится в байт. Из чего тогда должен состоять список значений сотен? На основе прошлых статей вы наверняка сможете написать процедуру, аналогичную по назначению "CALC", с использованием функции VAL калькулятора Бейсика. Она будет короче, не сомневаюсь. Но вот по времени исполнения она окажется совершенно не пригодной для обработки хистори, которая может состоять из сотен строк! Автохисторизатор затрачивает на обработку хистори обьемом 6-8 килобайт (типичное значение для одного сеанса сервера RABBIT BBS) всего около 4 секунд (не считая еще около 30 секунд на загрузку-выгрузку файлов с диска), выполняя, помимо подсчета баланса скачанных/закачанных секторов, еще и идентификацию звонивших на сервер пользователей по списку ph_v. P.S. Пользуясь случаем, хочу обратить внимание операторов BBS на появление CDOS 1.14. 14-я версия не виснет при появлении в линии длинного гудка или другого непрерывного тонального сигнала, пусть даже меняющегося по частоте. Я модернизировал процедуру приема, и теперь она безошибочно распознает посторонние сигналы. Если у вас повисал сервер, когда абонент бросал трубку без подачи команды END, или когда сервер поднимал трубку, а там - длинный гудок, попробуйте воспользоваться CDOS1.14. При обнаружении длинного гудка или другого постороннего сигнала трубка будет положена через 30 секунд. При наличии модемного сигнала работа происходит обычным образом. Прошу пользователей-не-сисопов не беспокоиться: 14-я версия - чисто серверная; для пользовательской работы она только вносит неудобства. Уважаемые сисопы, пожалуйста, скачивайте у меня (и не только) 14-ю CDOS, пользуйтесь! Инструкция с более подробным описанием программы имеется на сервере.
Другие статьи номера:
Вступление - содержание номера. |
BBS - список станций BBS ZXNet. |
Программирование - когда калькулятор бейсика противопоказан. |
Рассказ - Ну, юзер, погоди! (продолжение). |
Стихи - У СисОпа был помощник. |
Поиск - поиск игр, программ. |
Реклама - реклама и объявления. |
Обратная связь - контакты редакции. |
Похожие статьи:
В этот день... 21 ноября