Микро-80/Радио 1986-02,03/Программирование на Бейсике

Материал из Emuverse
Перейти к: навигация, поиск
Red copyright.png Данный материал защищён авторскими правами!

Использование материала заявлено как добросовестное, исключительно для образовательных некоммерческих целей.

Автор: Г. ЗЕЛЕНКО, В. ПАНОВ, С. ПОПОВ

Источник: http://retro.h1.ru/MK80/Basic/M80PrgBas.php

Одно из основных достоинств языка Бейсик — возможность разработки программ в диалоговом режиме. Вы, например, можете начать отладку программы. набрав всего одну строку. Убедившись в том, что эта строка «работает» так, как вы и предполагали, можно продолжить набор программы; если нет, то после анализа полученного результата можно быстро исправить обнаруженные ошибки. Кроме того, непосредственный режим работы интерпретатора предоставляет возможность проведения экспериментов по выявлению особенностей применения того или иного оператора или встроенной функции, что также способствует быстрому освоению языка.

В дальнейшем вы еще успеете оценить по достоинству преимущества, которые дает диалоговый режим при разработке программ, а пока попробуем сами составить программу, реализующую диалог с оператором. Начнем с постановки задачи. Допустим, необходимо разработать программу для проверки знаний арифметики у учащихся начальных классов. Сразу оговоримся, что описываемая ниже программа нужна нам прежде всего для ознакомления с возможностями языка Бейсик. Реальные программы проверки знаний требуют более тщательной проработки с привлечением специалистов по обучению и психологии.

Прежде всего разработаем «сценарий» работы программы. Мы умышленно пользуемся термином «сценарий», чтобы подчеркнуть диалоговый характер нашей будущей программы. Одним из возможных вариантов может быть такой.

На экране появляется вопрос:

КАK ТЕБЯ ЗОВУТ?

Ученик набирает на клавиатуре свое имя (например, АНТОН), и на экране тотчас возникает текст:

АНТОН, Я ХОЧУ ПРОВЕРИТЬ ТВОЕ ЗНАНИЕ АРИФМЕТИКИ. 
Я БУДУ ПРЕДЛАГАТЬ ПРИМЕРЫ, А ТЫ ПОСТАРАЙСЯ ИХ РЕШИТЬ.
ЕСЛИ ГОТОВ, НАЖМИ НА ЛЮБУЮ КЛАВИШУ.

После очистки экрана в его верхней части появляется следующая справочная информация:

ПОМНИ!
ЕСЛИ ПРИ ОТВЕТЕ ОШИБЕШЬСЯ И СЛУЧАЙНО НАЖМЕШЬ НЕ ТУ КЛАВИШУ, 
ТО НАЖМИ КЛАВИШУ "Я", А ЗАТЕМ НУЖНУЮ. 
ПОСЛЕ НАБОРА ОТВЕТА НАЖМИ КЛАВИШУ "ВК

Этот текст остается на экране до конца работы программы, а в центре экрана появляется вопрос:

АНТОН, СКОЛЬКО БУДЕТ 5 ПРИБАВИТЬ 2=?

При верном ответе на экран выводится:

МОЛОДЕЦ, АНТОН1 РЕШИ ЕЩЕ ПРИМЕР. 
ЕСЛИ ГОТОВ, НАЖМИ ЛЮБУЮ КЛАВИШУ.

Неверный ответ приводит к появлению на экране сообщения:

НЕПРАВИЛЬНО! 
ТЕБЕ, АНТОН, НАДО ПОДУМАТЬ.

Если за две попытки учащийся так и не смог решить пример, то на экране появляется текст:

ПЛОХО, АНТОН ТЫ НЕ СМОГ РЕШИТЬ ЭТОТ ПРИМЕР. 
ВОТ ПРАВИЛЬНОЕ РЕШЕНИЕ: 
5 ПРИБАВИТЬ 2 = 7 
РЕШИ ЕЩЕ ПРИМЕР. 
ЕСЛИ ГOTOВ, НАЖМИ ЛЮБУЮ КЛАВИШУ.

Ученик должен решить десять примеров. В зависимости от результатов в конце работы на экране высвечивается одно из следующих сообщений:

МОЛОДЕЦ, АНТОН, 
ТЫ ЗНАЕШЬ АРИФМЕТИКУ НА 5!
МОЛОДЕЦ, АНТОН, ТЫ ЗНАЕШЬ АРИФМЕТИКУ НА 4!
АНТОН, ТЫ ЗНАЕШЬ АРИФМЕТИКУ НА 3!
АНТ0Н, ТЫ ПЛОХО 3HAEШЬ АРИФМЕТИКУ!

Исходный текст программы, выполняющий описанные действия, приведен в табл. 1.

Таблица 1

10 RЕМ **************************************************
20 REM * ПРОГРАММА ПРОВЕРКИ ЗНАНИЙ АРИФМЕТИКИ *
30 REM * У УЧЕНИКОВ МЛАДШИХ КЛАССОВ *
40 RЕМ **************************************************
50 CLS: PRINT: PRINT
60 INPUT "КАК ТЕБЯ ЗОВУТ ": I$: РRINT: РRINT
70 PRINT I$: " , Я ХОЧУ ПРОВЕРИТЬ ТВОИ ЗНАНИЯ АРИФМЕТИКИ."
80 PRINT "Я БУДУ ПРЕДЛАГАТЬ ПРИМЕРЫ, А ТЫ ПОСТАРАЙСЯ ИХ РЕШИТЬ."
90 PRINT " ЕСЛИ ГОТОВ, НАЖМИ НА ЛЮБУЮ КЛАВИШУ."
100 A1 = USR(-2045)
110 X = l: W = 0
120 CLS: PRINT: PRINT
130 PRINT TAB(15): "ПОМНИ !"
140 PRINT "ЕСЛИ ПРИ ОТВЕТЕ ОШИБЕШЬСЯ И СЛУЧАЙНО НАЖМЕШЬ"
150 PRINT "НЕ ТУ КЛАВИШУ, ТО НАЖМИ КЛАВИШУ "Я" ЗАТЕМ НУЖНУЮ."
170 PRINT "ПОСЛЕ НАБОРА ОТВЕТА НАЖМИ КЛАВИШУ "BK": PRINT
180 R=ABS(INT(RND(1)*20 - 10))
190 IF R=0 OR R=l THEN 180
200 Q=ABS(INT(RND(1)*20 -10))
210 IF Q=0 OR Q=1 THEN 200
220 KL=INT(RND(1) * 5)
230 IF KL=0 ТHEN 220
240 ON KL GOSUB 510, 550, 600, 630
250 PRINT: PRINT I$: " СКОЛЬКО БУДЕТ "; P; U$; R; "=";
260 INPUT D
270 IF D=Q ТHEN 370
280 PR I NT: PR I NT " НЕПРАВИЛЬНО !"
290 PRINT "ТЕБЕ, "; I$; " , НАДО ПОДУМАТЬ."; PRINT
300 PRINT I$; " СКОЛЬКО БУДЕТ "; P; U$; R; "=";
310 INPUT D: PRINT
320 IP D=Q ТHEN 370
330 РRINT "ПЛОХО, "; I$; " ТЫ НЕ СМОГ РЕШИТЬ ЭТОТ ПРИМЕР."
340 PRINT " ВОТ ПРАВИЛЬНОЕ PЕШЕНИЕ "
350 PRINT TAB(8); P; U$; R; "="; Q: PRINT
360 GOTO 390
370 W=W +1
380 PRINT "МОЛОДЕЦ "; I$; " ПРАВИЛЬНО. ": PRINT
390 IF X=10 THEN 450
400 X=X + 1
410 PRINT "РЕШИ ЕЩЕ ПРИМЕР."
420 PRINT "ЕСЛИ ГОТОВ, TO НАЖМИ ЛЮБУЮ КЛАВИШУ"
430 A1=USR(-2045)
440 GOTO 120
450 PRINT: PRINT
460 IF W=10 THEN РRINT "МОЛОДЕЦ, "; I$; ", ТЫ ЗНАЕШЬ АРИФМЕТИКУ НА 5!"
470 IF W=8 OR W=9 THEN PRINT "МОЛОДЕЦ, "; I$; ", ТЫ ЗНАЕШЬ АРИФМЕТИКУ      НА 4!"
480 IF W=8 OR W=7 THEN PRINT I$; ", ТЫ ЗНАЕШЬ АРИФМЕТИКУ НА 3!"
490 IF W < 6 THEN PRINT I$; ", ТЫ ПЛОХО ЗНАЕШЬ АРИФМЕТИКУ !"
500 STOP
510 U$=" ПРИБАВИТЬ "
520 G=G * 3: R=R * 3
530 P=G: Q=G + R
540 RETURN
550 U$=" ОТНЯТЬ "
560 IF G=R THEN G=G +3
570 G=G * 3: R=R * 3
580 IF G < R THEN Q=G: G=R: R=Q
590 P=0: Q=G - R: RETURN
600 D$ " УМНОЖИТЬ НА "
610 P=0: Q=G * R
620 RETURN
630 U$=" PAЗДЕЛИТЬ HA "
640 P=G * R: Q=R
650 RETURN

Рассмотрим ее особенности. Прежде всего обратим внимание на то. каким образом формируются текстовые сообщения, появляющиеся на экране дисплея. В соответствии с нашим сценарием возникает необходимость вывода на экран сообщений, в которых встречается имя отвечающего на вопросы (символьная переменная I$). Для этой цели используется разделитель «;» (точка с запятой).

В строках 100 и 430 происходит вызов стандартной полпрограммы монитора «ввод кода символа с клавиатуры», адрес которой равен F803Н в шестнадцатиричной системе счисления. Это вызвано необходимостью приостановки выполнения программы до тех пор, пока не будет нажата любая клавиша. Значение, возвращаемое подпрограммой, в данном случае не используется. В строках программы 180 и 200 формируются случайые числа, предназначенные для генерации операндов очередной задачи. Вид действия (сложение, вычитание, умножение или деление) определятся следующим образом. В строке 220 переменной KL присваивается значение 2. 3 или 4. В строке 240 в зависимости от значения этой переменной происходит вызов соответствующей подпрограммы. В этик подпрограммах формируются операнды предлагаемого примера. Символьной переменной U$ присваивается определенное значение в зависимости от вида арифметической операции.

Переменная Х хранит значение, равное числу заданных примеров, а значение переменной W равно числу верных ответов.

При разработке программ и при работе с ЭВМ часто возникает необходимость перевода чисел из одной системы счисления в другую. Пользуясь известными правилами, это можно сделать и вручную. В табл. 2 приведен пример программы, позволяющей возложить эту трудоемкую работу на микро-ЭВМ. Программа переводит числа из десятичной системы счисления в шестнадцатиричную и наоборот, широко используя встроенные функции Бейсика для работы с символьными данными.

Таблица 2.

10 RЕМ **********************************************
20 RЕM * ПРОГРАММА ПЕРЕВОДА ЧИСЕЛ ИЗ ШЕСТ- *
30 REM * НАДЦАТИРИЧНОЙ СИСТЕМЫ СЧИСЛЕНИЯ В *
40 RЕM * ДЕСЯТИЧНУЮ И НАОБОРОТ. *
50 RЕМ **********************************************
100 INPUT "ВВЕДИТЕ (Д)ЕС. или (Ш)ЕСТ. ";S$
110 IF S$="Ш" OR S$="Д" THEN 130
120 GOTO 100
130 IF S$="'Д" THEN 160
140 INPUT "ШЕСТНАДЦАТИРИЧНОЕ ЧИСЛО "; N$
150 N=0: GOSUB 1000: GOТО 100
160 INPUT "ДЕСЯТИЧНОЕ ЧИСЛО "; N
170 GOSUB 1100: GОТО 100
1000 REM ПЕРЕВОД ШЕСТ. -> ДЕС.
1010 FOR I=1 TO LEN(N$)
1020 D=ASC(MIDS(N$. I, l))-48
1030 IF D < 10 THEN 1080
1040 D=D - 7
1050 IF D < 0 OR D >=l6 THEN N=0: GOTO 1080
1060 N=N * 16 + D
1070 NEXT I1080 PRINT "ДЕСЯТИЧНОЕ ЧИСЛО = "; N
1090 RETURN1100 REM ПЕРЕВОД ДЕС. -> ШЕСТ.
1110
1120 L=INT(N/16)
1130 M=N - 16 * L
1140 IF M < 10 THEN 1160
1150 M=М + 7
1160 N=L: A$=CHR$(M +48) + A$
1170 IF N >=1 THEN 1120
1180 PRINT "ШЕСТНАДЦАТИРИЧНОЕ ЧИСЛО = "; A$
1190 RETURN

Начинается программа с запроса ввода с клавиатуры одной из букв «Д» или <Ш". При ошибочном вводе запрос повторяется. Далее, в зависимости от выбранного режима, оператор должен ввести десятичное или шестнадцатеричное целое число. При переводе чисел из шестнадцатеричной системы счисления в десятичную в программе используется то обстоятельство. что коды символов, отображающих шестнадцатеричные числа (0-9, A-F), равны соответственно 48-57, 65-70. В подпрограмме преобразования проводится проверка на корректность набранного числа (оно должно содержать только допустимые символы). При обнаружении ошибки ввода результат преобразования равен нулю.

В подпрограмме перевода из десятичной системы счисления в шестнадцатеричную вычисляется код очередной цифры и все число «накапливается» в символьной переменной A$. Здесь каких-либо специальных проверок не предусмотрено, так как сам интерпретатор осуществляет проверку корректности ввода числовых данных.

В тексте описываемой программы процедуры преобразования оформлены в виде подпрограмм. Это позволяет использовать их в ваших программах на Бейсике, в которых требуется ввод и отображение данных в шестнадцатеричной системе счисления. К таким программам относятся МОНИТОР, АССЕМБЛЕР, ДИЗАССЕМБЛЕР и др. О назначении первых двух уже говорилось в предыдущих статьях. ДИЗАССЕМБЛЕР позволяет перевести программу, написанную в машинных кодах, в мнемонику ассемблера и может быть реализован на Бейсике.

Описанный в журнале интерпретатор имеет средства, позволяющие программам на Бейсике работать с подпрограммами, написанными на ассемблере или в машинных кодах. Для вызова таких подпрограмм служит встроенная функция USR(X). Рассмотрим пример, иллюстрирующий ее использование.

Алфавитно-цифровая клавиатура является в настоящее время самым распространенным устройством ввода данных в ЭВМ. Однако, чтобы быстро и безошибочно вводить данные с ее помощью, нужен немалый опыт. Кроме того, если использование такой клавиатуры для ввода символьной информации вполне естественно, то ввод графических данных или указывание на какой-либо объект на экране с ее помощью весьма затруднены. В современных персональных микро-ЭВМ для выполнения этих действий используют ряд специальных устройств. К ним относятся такие известные устройства, как «джойстик» и «мышь». Первое из них представляет собой электромеханическое устройство, в котором два или три переменных резистора управляются одной рукояткой, выполненной в виде рычажка .Иногда вместо переменных резисторов используют емкостные датчики. Недостатком этого устройства является довольно сложная конструкция.

Манипулятор «мышь» представляет собой небольшую коробочку с клавишами, соединяемую с ЭВМ кабелем — «хвостом». Определенное внешнее сходство и породило название манипулятора — «мышь». Перемещение манипулятора по поверхности стола приводит к взаимно однозначному перемещению курсора по экрану дисплея. Конечно, выдаваемую манипулятором информацию о положении программное обеспечение может трактовать и иначе. Например, в графическом режиме с помощью манипулятора можно рисовать на экране различные фигуры, а в игровых программах управлять перемещением каких-либо объектов по экрану. Однако чаще всего манипулятор используют именно для указывания.

M80PrgBasP1.png
M80PrgBasP2.png

Для Микро-80 разработано простое устройство ввода данных, функционально аналогичное описанным выше. Его принципиальная схема изображена на рис.1, возможный вариант внешнего оформления — на рис.2. Устройство состоит из двух одновибраторов (DA1, DA2), в частотозадающие цепи которых включены переменные резисторы R4 и R5. Длительность выходных импульсов пропорциональна углу поворота движка соответствующего резистора. При вводе данных резистором R4 (ось X) управляют большим пальцем правой руки. резистором R5 (ось X) — средним, а кнопкой SBI — указательным.

Для подключения к микро-ЭВМ используют свободные порты ППА КР580ИК55, предназначенного для обслуживания клавиатуры. Можно подключить устройство и иначе, но в этом случае необходимо соответственно изменить подпрограммы его обслуживания.

Таблица 3.

;подпрограмма
;РОТХ - ось Х
1960 1600	РОТХ:	MVI	0,0	;счетчик длит. импульса
;используем операции устам
;сброс битов канала С
1962 3E08 		MVI	А,8Н	;формирование
1964 D304 		OUT 	4Н 	;импульса запуска
1966 ЗЕ09 		MVI 	А,9H 	;на выволе КС4
1968 D304 		OUT 	4Н 	;порта клавиатуры
196А С37719 	JMP 	POTXY 	;общие действия по Х и Y
;подпрограмма
;РОТУ - ось Y
196D 1600 	POTY: 	MVI 	0,0
196F 3E0A 		MVI 	A,0AH 	;формирование
1971 D304 		OUT 	4Н 	;импулъса запуска
1973 3E0B 		MVI 	А,0ВН 	; на выводе КС5
1975 D304 		OUT 	4Н 	; порта клавиатуры
1977 DB05 	POTXY:	IN 	5H
1979 14 		INR 	D 	;СЧЕТЧИК * I
197А Е608 		ANI 	8Н 	; выделяем 3 разряд
197С СА7716 	JZ 	POTXY 	; импульс продолжается
197F 7А 		MOV 	А,D 	;импул&с закончился
1980 С9 		RET

Таблица 4.

10 REM **********************************************
20 REM * ПРОГРАММА РИСОВАНИЯ НА ЭКРАНЕ              *
30 REM * С ПОНОЩЬЮ УСТРОЙСТВА УПРАВЛВНИЯ            *
40 REM * КУРСОРОМ, ИСПОЛЬЗУЮТ ПОДПРОГРАММЫ          *
50 REM * В МАШИННЫХ КОДАХ ДЛЯ ОПРЕДЕЛЕНИЯ           *
60 REM * КООРДИНАТ.                                 *
70 REM ***********************************************
80 OUT 4 , 131: 		REM НАСТРОЙКА ПОРТА
90 X = (USR(6496): 		REM ВЫЗОВ ПОДПРОГРАММЫ РОТХ
100 IF Х > 127 THEN X = 127
110 Y = USR(6509): 		REM ВЫЗОВ ПОДПРОГРАММЫ РОТУ
120 IF У > 63 ТНЕN У = 63
130 REM ПРОВЕРКА СОСТОЯНИЯ КНОПКИ
140 IF INP(6) AND 128 THEN S = 1: GOTO 150
150 PLOT X, Y, S
160 GOTO 90

Запуск одновибраторов (по спаду импульса на входе 2) и определение длительности импульса производится подпрограммой, приведенной в табл. 3. После выдачи импульса запуска она считывает состояние порта ввода N5, к разряду КС3 которого через элемент DD2.2 подключены выходы одновибраторов. При выходе из подпрограммы содержимое аккумулятора соответствует углу поворота движка переменного резистора. Конденсаторы С1 и СЗ подбирают таким образом, чтобы при полном повороте движков переменных резисторов R4 и R5 подпрограммы РОТХ и POTY возвращали числа 127 (размер по горизонтали) и 63 (размер по вертикали) соответственно.

Для хранения подпрограмм в машинных кодах, используемых совместно с интерпретатором, специально выделена небольшая область памяти с адресами с 1960Н по 19FFH. Кроме приведенных подпрограмм, вы можете разместить здесь (если, конечно, хватит места) и свои. После этого на магнитофон целесообразно записать эту новую версию интерпретатора, что позволит в дальнейшем пользоваться библиотекой подпрограмм, расширяющих возможности интерпретатора.

В табл.4 приведен текст программы на Бейсике, которая предполагает использование описанного выше устройства управления курсором. Программа позволяет рисовать на экране дисплея разнообразные фигуры. В начале программы производится настройка порта (строка 80). Состояние кнопки, расположенной в устройстве управления курсором, определяется непосредственно в программе на Бейсике с помощью функции INP(X). В строках 90 и 110 происходит вызов подпрограмм в машинных кодах (функция USR(X). Чтобы избежать в процессе работы программы появления ошибки 08, в ней предусмотрена коррекция значений, возвращаемых подпрограммами РОТХ и POTY.

Мы надеемся, что вы сумеете найти и более удачные варианты применения описанного устройства.

Последний пример, который мы рассмотрим, посвящен разработке программ, организующих вывод на экран дисплея графических изображений. Формирование рисунков, состоящих из отрезков прямых линий и отдельных точек, не вызывает обычно каких-либо осложнений — для этого служат графические операторы Бейсика (CLS, PLOT, LINE). Необходимо только постоянно следить за тем, чтобы координаты, задаваемые этим операторам, не выходили за допустимые пределы, иначе интерпретатор выдаст сообщение об ошибке номер 08

Формирование изображений окружностей и эллипсов — более сложная задача. Приводимая в табл.5 универсальная подпрограмма позволяет «начертить» окружность произвольного радиуса в любом месте экрана. Эту подпрограмму можно включить в состав вашей программы и обращаться к ней при помощи оператора GOSUB 9000. Вообще говоря, так же, как и в случае с библиотекой подпрограмм в машинных кодах, о которой мы говорили выше, вы можете создать и библиотеки подпрограмм на Бейсике. Например, к описываемой ниже подпрограмме можно добавить подпрограммы для формирования изображения и других геометрических фигур. В этом случае основная программа будет состоять из операторов присваивания, подготавливающих параметры для подпрограмм и операторов вызова подпрограмм.

Таблица 5.

9000 REM *************************************
9010 REM * ПОДПРОГРАМНА ВЫЧЕРЧИВАНИЯ         *
9020 RЕМ * ИЗОБРАЖЕНИЙ ОКРУЖНОСТЕЙ И         *
9030 REM * ЭЛЛИПСОВ.                         *
9040 RЕМ *************************************
9050 Р2 = 3.14159: REM УГОЛ = 2 ПИ
9060 REM ДЛЯ ВЫЧЕРЧИВАНИЯ ДУГ НАДО
9070 REM изменить КОНСТАНТЫ в ОПЕРАТОРЕ
9080 REM ИНИЦИАЛИЗАЦИИ ЦИКЛА
9100 FOR F9 = 0 TO P2 STEP 0.1
9110 X9 = XC + RC * KX * SIN(F9)
9120 Y9 = YC + RC * KY * COS(F9)
9130 IF X9 < 0 THEN X9=0
9140 IF X9 > 127 THEN X9 = 127
9150 IF Y9 < 0 THEN Y9 = 0
9160 IF У9 >63 THEN Y9 = 63
9170 PLOT X9, Y9, FL
9180 NEXT F9
9190 RETURN

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

Для подпрограмм, входящих в библиотеку, принято назначать большие номера строк. Поэтому при написании новой программы сначала загрузите с магнитной ленты вашу «библиотеку», а основную программу набирайте со строки с номером 10. И еще один совет. В качестве подпрограмм целесообразно оформлять только часто выполняемые процедуры, с остальными этого лучше не делать, так как вызов подпрограммы и возврат из нее требуют определенных затрат времени.

Перед обращением к подпрограмме (табл.5) необходимо задать значения переменным, с которыми она работает. Переменные XC и УС определяют координаты центра окружности, a RC — ее радиус. Переменными КХ и KY задают степень сжатия или растяжения по осям Х и Y соответственно. Изменяя их значения, можно получать изображения окружности, вытянутые вдоль оси Х или Y. При КХ и KY, равных 1, на экране формируется эллипс, вытянутый вдоль оси Y. Это объясняется особенностями телевизионного растра и нашего дисплейного модуля. Поэтому для получения изображения окружности параметр KY должен быть равен 0,8КХ.

Taблица 6

10 REM **************************************
20 REM * ПРОГРАММА ФОРМИРОВАНИЯ             *
30 RЕМ * ИЗОБРАЖЕНИЯ ОЛИМПИЙСКОГО           *
40 REM * СИМВОЛА, ИСПОЛЬЗУЕТ ПОД-           *
50 RЕМ * ПРОГРАММУ "КРУГ"                   *
60 REM **************************************
70 CLS80 KX = l: KY = 0.8: REM КОЭФФИЦИЕНТЫ  СЖАТИЯ
90 RС = 10: RЕМ РАДИУС ОКРУЖНОСТЕЙ
100 YC = 40
110 XC = 40: GOSUB 9000: REM 1 КРУГ
120 XC = 56: GOSUB 9000: REM 2 КРУГ
130 XC = 72: GOSUB 9000: REM 3 КРУГ
140 YC = 25
150 XC = 48: COSUB 9000: REM 4 КРУГ
160 XC = 64: COSUB 9000: REM 5 КРУГ
170 STOP

В подпрограмме для вычисления координат точек, лежащих на окружности заданного радиуса R, использованы известные соотношения:

X = XC + RC * sin (π), 
Y = YC + RC * cos (π), где ХС и YC – координаты центра окружности.

В подпрограмме предусмотрены контроль и коррекция координат центра окружности по следующим правилам:

  • если ХС < 0, то ХС = 0;
  • если ХС > 127, то ХС = 127;
  • если YC < 0, то YC = 0;
  • если YC > 63, то YC = 63.

Поэтому при выполнении подпрограммы сообщение об ошибке 08 не возникает.

В табл.6 приведена программа, формирующая на экране изображение олимпийского символа — пяти пересекающихся колец, в которой использована описанная подпрограмма.

ПРОГРАММА И ПАМЯТЬ ЭВМ

При разработке программ на любом языке программирования практически всегда приходится учитывать такие факторы, как время выполнения программы и необходимый для этого объем памяти. Оба параметра следует по возможности уменьшать, это позволит к результат получить быстрее, и учесть ограничения, связанные с небольшим объемом памяти ЭВМ. Однако добиться одновременно и того, и другого — довольно сложная задача.

К программам на Бейсике сказанное имеет самое прямое отношение, особенно если транслятор с языка высокого уровня (как в нашем случае) реализован в виде интерпретаторы и объем памяти для хранения программ и переменных мал. Рассмотрим несколько приемов, позволяющих уменьшить требуемый для работы программ объем памяти. При работе интерпретатора в ОЗУ одновременно находятся сам интерпретатор, текст программы на Бейсике и различные переменные и константы, встречающиеся в программе. Появление сообщения об ошибке 07, как при наборе текста программы, так и при ее выполнении, указывает на то, что для данной программы объем памяти недостаточен. Как следует поступать в таких случаях? Прежде всего можно сократить в программе комментарии, уменьшить длину текстовых сообщений, использовать однобуквенные имена для переменных. Объем памяти, занимаемый текстом программы, можно также уменьшить, набирая в каждой строке не по одному, а по несколько операторов, отделяя их друг от друга символом «:» — двоеточием (почему происходит такое сокращение вы поймете, познакомившись с дополнительными сведениями об интерпретаторе).

Если после этих переделок объем памяти все равно недостаточен, то следует критически проанализировать необходимость использования тех или иных переменных и особенно переменных с индексами — массивов. Для массивов следует резервировать ровно столько ячеек памяти, сколько для них в действительности потребуется. Например, если массив А(1) состоит из 5 элементов, а вы его не описали оператором DIM, то по умолчанию интерпретатор выделит в памяти место для 10 элементов массива, и это приведет к потере 20 байт памяти. Для того чтобы оценить к каким затратам памяти тот или иной вариант реализации алгоритма, удобно пользоваться встроенной функцией FRE(0). Попробуйте посмотреть, чему равно значение этой функции до загрузки программы в память, после загрузки и после выполнения программы. Для этого достаточно в непосредственном режиме набрать PRINT FRE(0). Таким образом, вы сможете определить, сколько места в памяти занимает текст программы и сколько ячеек отводится для хранения переменных и констант.

ПРОГРАММА И ВРЕМЯ ЕЕ ВЫПОЛНЕНИЯ

Сократить время выполнения программы несколько сложнее, чем ее объем. Для этого прежде всего необходимо определить ту часть программы, на выполнение которой затрачивается наибольшие время.

Известно, что циклическая часть программы. занимающая всего 5 % исходного текста, требует для своего выполнения обычно почти 95 % времени работы всей программы. Вы должны обнаружить эти «критические» циклы в программе и попытаться уменьшить время их выполнения. Вначале надо убедиться, что все операторы, входящие в этот цикл, действительно должны выполниться внутри него. Например, если значение переменной не изменяется в цикле (см. табл. 7, пример 1), то ее инициализацию следует производить вне цикла (пример 2), что сократит время его выполнения. Уменьшить время выполнения программы можно также некоторым видоизменением операторов, входящих в тело цикла. В примере 3 (табл.7) обнуление элементов массива проводится в цикле. Если переписать эту программу, как показано в примере 4, то время выполнения операторов FOR.. …..NEXT значительно сократится.

Во многих случаях, если число элементов массива невелико, имеет смысл вообще отказаться от оператора цикла и проводить инициализацию элементов массива следующим образом:

10 А(1) = 0: А(2) = 0: А(3) = 0: А(4) = 0: А(5)=0.

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

IF K * R/T - D > 0 THEN E = K * R/T + 1 

Таблица 7


10 RЕМ **************** 10 REM ***************
20 REM * ПРИМЕР 1 * 20 RЕМ * ПРИМЕР 2 *
30 REM *************** 30 REM ***************
40 FOR I = 0 TO 340 40 A = SIN(1.45) * 30
50 A = SIN(1.45) * 30 50 FOR I = 0 TO 340
60 B(I) = A * I/4 60 B(I) = A * I/4
70 NEXT I 70 NEXT I
80 STOP 80 STOP
10 REM ************** 10 REM **************
20 REM * ПРИМЕР 3 * 20 REM * ПРИМЕР 4 *
30 RЕМ ************** 30 REM ***************
40 FOR I = 1 TO 60 40 FOR I = 1 TO 30
50 S (I) = 0 50 S(I) = 0: S(I + 30) = 0
60 NEXT 1 60 NEXT I
70 STOP 70 STOP


дважды определяется величина K*R/T. Если переписать эту строку следующим образом:

Q=K*R/T: IF Q-D>0 THEN E=Q+l, 

то вычисление значения новой переменной Q будет проведено только один раз. «Плата» за сокращение времени работы программы - необходимость резервирования нескольких ячеек памяти для хранения переменной Q.

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

Z1 = Y(A) + 10: Z2 = Y(A) + 5: Z3 = Y(А) + 21 

целесообразнее определять так:

Z1 = Y(A) + 10: Z2 = Z1 - 15: Z3 = ZI + 10.

Особенно большой выигрыш во времени может быть получен, если подобные вычисления проводятся в теле цикла или в программе использованы многомерные массивы.

Мы рассмотрели ряд конкретных примеров, позволяющих сократить время выполнения программ на Бейсике, но, конечно, наиболее ощутимые результаты можно получить, если воспользоваться функцией USR(X) и запрограммировать критичный по времени выполнения фрагмент алгоритма на языке Ассемблер.

Таким образом, перед программистом всегда стоит проблема выбора наилучшею варианта реализации программы с точки зрения времени ее выполнения, занимаемого объема памяти, простоты и ясности.

ДОПОЛНИТЕЛЬНЫЕ СВЕДЕНИЯ ОБ ИНТЕРПРЕТАТОРЕ

Посмотрим теперь, как хранится программа на Бейсике в памяти ЭВМ. Это может оказаться полезным в случае какого-либо сбоя в работе микро-ЭВМ, который может привести к потере набранной программы. Кроме того, приводимые ниже сведения помогут восстановить программу, введенную с ошибками с магнитной .ленты, и разобраться в организации структуры данных в ваших программах.

M80PrgBasP3.png

На рис.3 показано, как распределяется память в микро-ЭВМ при работе интерпретатора Бейсика. Текст программы хранится в памяти сразу же после кодов интерпретатора, за ним следует область памяти, выделенная для хранения переменных. Вблизи верхней границы ОЗУ имеется специальная область (стек), отведенная для «внутренних» нужд интерпретатора.

Каким образом строка программы представлена на микро-ЭВМ. Просматривая содержимое памяти с помощью директив «D» и «L» Монитора, вы можете обнаружить, что хранимая в памяти информация не похожа на то, что было набрано на клавиатуре. Это вполне объяснимо, так как микро-ЭВМ «понимает» только двоичные коды, то есть способна «понять» код той или иной буквы, а не саму букву.

Поэтому строки программы хранятся в памяти в виде двоичных кодов и переводятся в символьный вид только в случае просмотра текста программы по директиве интерпретатора LIST. Однако это только одна сторона вопроса. Если бы каждый вводимый символ программы занимал в памяти одну ячейку (1 байт), то это потребовало бы, во-первых, очень большого объема памяти и, во-вторых, программа выполнялась бы очень медленно.

Вместо того, чтобы хранить в памяти коды всех символов исходного текста программы, можно закодировать каждое ключевое слово всего одним байтом. Это вполне возможно, так как из 256 возможных двоичных кодов (28=256), которые можно записать в одну ячейку памяти, для кодирования алфавитно-цифровых символов используется только 128. Двоичные коды, у которых старший бит равен 1, и использованы для кодирования ключевых слов языка Бейсик (табл.8). Что же дает такое «сжатие» информации? Очень многое. Например, если в программе 100 раз встречается оператор GOSUB, то кодирование позволяет сэкономить 400 байт памяти!

Таблица 8

ТАБЛИЦА КОДОВ КЛЮЧЕBЫХ СЛОВ БЕЙСИКА

СЛОВО ШЕСТ. ДЕС. СЛОВО ШЕСТ. ДЕС. СЛОВО ШЕCT. ДЕС.
CLS 80 128 CONT 97 151 SGN AD 174
FOR 81 129 LIST 98 152 INT AB 175
NEXT 82 130 CLEAR 99 153 ABS AF 176
DATA 83 131 MLOAD 9A 154 USR B0 177
INPUT 84 132 MSAVE 155 PRE Bl 178
DIM 85 133 NEW 156 INP B2 179
READ 86 134 TAB( 9D 157 POS B3 180
CUR 87 138 TO 9E 158 SQR B4 181
GOTO 88 136 SPC( 9F 159 RND B5 182
RUN 88 137 FN А0 160 LOG B6 183
IF 138 THEN Al 161 EXP B7 184
RESTORE 139 NOT A2 162 COS B8 185
GOSUB 8C 140 STEP A3 163 SIN B9 186
RETURN 8D 141 + A4 164 TAN ВА 187
REN 8E 142 A5 165 ATN BB 188
STOP 8F 143 * A6 166 PEEK ВС 189
OUT 90 144 / A7 167 LEN BD 190
ON 91 145 A8 168 STR$ BE 191
PLOT 92 146 AND A9 169 VAL BF 192
LINE 93 147 OR AA 170 ASС C0 193
POKE 94 148 > AB 171 CHR$ Cl 194
PRINT 95 149 AC 172 LEFT$ С2 195
DEF 96 150 < AD 173 RIGHT$ СЗ 196
            MID$ C4 197
M80PrgBasP4.png

На рис.4 показан формат строки программы на Бейсике в том виде, в каком она хранится в памяти микро-ЭВМ. В начале каждой строки два байта отведены для хранения указателя адреса начала следующей строки программы, следующие два байта хранят номер строки, а заканчивается она байтом, заполненным одними нулями. Таким образом, текст программы хранится в памяти в виде специальной структуры данных. называемой в литературе «односвязным списком».

Заканчивая обработку очередной строки программы, интерпретатор последовательно просматривает указатели списка до тех пор, пока не будет найдена строка с требуемым номером. Конец списка помечается двумя «нулевыми» байтами. Вы таким же образом можете вручную (с помощью директив Монитора) определить, где заканчивается программа, просматривая указатель списка до тех пор, пока не обнаружите три смежных байта, заполненных нулями. Во многих практических случаях, воспользовавшись рассмотренными рекомендациями, можно восстановить программу, в которой в результате сбоя была нарушена целостность списка. После восстановления структуры списка необходимо изменить значения, хранящиеся в ячейках памяти 0245Н и 0246Н. В этих ячейках хранятся значения соответственно младшего и старшего байта конечного адреса программы. Этот адрес на двойку превосходит адрес первого байта маркера конца списка.

Г. ЗЕЛЕНКО, В. ПАНОВ, С. ПОПОВ

г. Москва

Отсканировано с журнала Радио № 3 1986 г.
Отредактировано Лесных Ю. И. 1999 г.