ГЛАВА IV. ФУНКЦИИ И ПОДПРОГРАММЫ Любая по-настоящему полезная классификация содержит от трех до шести категорий. Энон В MSX-BASIC различают следующие основные типы функций: 1) встроенные функции: а) встроенные числовые функции; b) встроенные функции преобразования; c) встроенные функции для работы со строками; 2) функции пользователя. Встроенные функции называют иначе с т а н д а р т н ы м и функциями, вычисление значений которых реализуется специальными программами, постоян- но находящимися в памяти компьютера.Каждая такая программа имеет уникаль- ное и м я, по которому и происходит обращение к ней (SIN, LOG, VAL, MID$ и т.д.). К функциям п о л ь з о в а т е л я относятся те функции,которые поль- зователь определяет в программе сам. Заметим, что встроенные ч и с л о в ы е функции мы уже изучили (см. раздел I.7.4.)! IV.1. ВСТРОЕННЫЕ ФУНКЦИИ ПРЕОБРАЗОВАНИЯ Напомним, что множество значений строковых переменных - это множество упорядоченных наборов символов. Упорядоченность означает, что строковые значения различаются не только набором, но и последовательностью символов, например, "краб" и "брак"- это разные значения. Количество символов в зна- чении строковой переменной меняется в пределах от 0 до 255. В дальнейшем, с т р о к о й A$ или с л о в о м A$ будем называть зна- чение строковой переменной A$. Обратим особое внимание на то, что строка может не содержать символов. Такая строка называется п у с т о й и обозначается ""(кавычки идут под- ряд). Длина этой строки равна 0. Не следует путать пустую строку со стро- кой, содержащей п у с т о й символ (пробел). Строка,содержащая пробел,обо- значается " "(между кавычками есть пробел) и имеет длину 1. Отметим, что символ "пробел" - равноправный с остальными символ! IV.1.1. LEN - ф у н к ц и я Ее общий вид LEN(α) где: LEN ("LENgth"-"длина") - служебное слово; α - строковое выражение. Результатом функции LEN(α) является длина значения строкового выраже- ния α (или что то же самое,количество символов в строке α),LEN(α)∈[0,255]. Напомним, что в том месте дисплейной строки,где надо обратить Ваше вни- мание на наличие символа пробел (" "), мы будем использовать символ "·". П р и м е р 1. ───────────── NEW Оk 10 X$="парк": Y$="детский парк":Z$=" ау! ":u$="":w$=" " 20 PRINT LEN(X$);LEN(Y$);LEN(Z$);len(u$);len(w$) run ·4··12··5··0··1 Ok Еще раз подчеркнем,что п р о б е л - такой же символ,как,например "а"! Эта функция, пожалуй,чаще всего используется при работе со строковыми переменными. С ее помощью, например, можно определить,не является ли стро- ка пустой до выполнения действий, которые не могут выполняться над пустой строкой (""). П р и м е р 2. 10 IF LEN(A$)>0 THEN PRINT "Все в порядке!" ELSE PRINT ───────────── "Строка пустая!" 'Проверка, является ли строка пустой, т.е. не содержащей ни одного символа. П р и м е р 3. NEW ───────────── Ok 10 'Выравнивание слов по правому краю. 20 FOR I=1 TO 3:READ A$ 30 ?TAB(20-LEN(A$));A$:NEXTI 40 DATA "Хэкер-","фанатичный","программист" run ··············Хэкер- ··········фанатичный ·········программист Ok Сравните функцию LEN() с функцией длин (А), где длин(А) - длина текс- ──── ──── та A, в школьном алгоритмическом языке [11, с.53]! IV.1.2. INSTR - ф у н к ц и я Общий вид функции INSTR: INSTR([n,]α,β) Здесь: INSTR("IN STRing"-"в строке") - служебное слово; n - арифметическое выражение, целая часть значения которого должна принадлежать [1,255] (по умолчанию n=1); α - строковое выражение; β - строковое выражение. Эта функция исследует значение строкового выражения α слева направо, начиная с символа, номер которого задан величиной целой части значения па- раметра n или с его первого символа (по умолчанию).Значением функции явля- ется номер позиции в значении α, с которой значение β первый раз встреча- ется в α. Если значение β не найдено,то результатом функции INSTR являет- ся 0 (как говорят,"функция INSTR возвращает значение 0").Значением выраже- ния α или β может быть пустая строка. При работе с функцией INSTR возможны следующие ошибки. Сообщение "Illegal function call" ("Н е п р а в и л ь н ы й в ы з о в ф у н к ц и и") возникает, если значение арифметического выражения n неположительно, а сообщение "Type mismatch" ("Н е с о о т в е т с т в и е т и п о в"), если α или β нестрокового типа. Это сообщение выдается очень часто при ра- боте с функциями преобразования и с функциями для работы со строками; как правило, причиной этого служит пропущенный знак "$" после имени строковой переменной или имени строковой функции. П р и м е р. ─────────── NEW Оk 10 INPUT X$,Y$,N 20 PRINT INSTR(N,X$,Y$) run run run run ? ХАФАНАНА,НА,3 ? ХАФАНАНА,НА,100 ? "","",5 ? KEN,"",2 5 0 0 2 Ok Ok Ok Ok run run ? Кузьма Кузьмич,Кузьм,1.5 ? Кузьма Кузмич,Кузьм,0 1 Illegal function call in 20 Ok Ok IV.1.3. VAL - ф у н к ц и я Ц и ф р о в а я строка - это строка,содержащая любое количество распо- ложенных в любом месте строки пробелов, знак "плюс" или "минус", десятич- ные цифры и десятичную точку. Цифровая строка также может содержать: a) запись числа в экспоненциальном представлении (в форме с плавающей точкой); b) запись числа в двоичном, восьмеричном и шестнадцатеричном представ- лениях; в этих случаях цифровая строка называется д в о и ч н о й , в о - с ь м е р и ч н о й и ш е с т н а д ц а т е р и ч н о й цифровой (сим- вольной) строкой соответственно. В ряде случаев удобнее работать с числами, а не с их представлениями в виде цифровых строк. Цифровую строку можно преобразовать в числовое значе- ние с помощью функции преобразования VAL, общий вид которой: VAL(α) где: VAL("VALue"-"значение") - служебное слово; α - строковое выражение. Преобразование начинается с крайнего левого символа значения строково- го выражения α и заканчивается, когда преобразован последний символ значе- ния α, либо когда встретился нецифровой символ. П р и м е р ы: ───────────── Ok Ok print VAL("12.5E-3") print val("&b1");val("&o76");val("&hF") .0125 ·1··62··15 Ok Ok Если строка является пустой или начинается с нецифрового символа, то функция VAL возвращает значение 0. П р и м е р ы: ───────────── 1) Ok 2) Ok ? VAL("a12");VAL("23A12:");VAL("") ? VAL("-1.24") ·0··23··0 -1.24 Ok Ok Если одним из символов цифровой строки является восклицательный знак, то в зависимости от его расположения возможны следующие случаи. П р и м е р ы: ───────────── 1) Ok ? VAL("1234.56789!") ·1234.57 ◀─── результат преобразования: число одинарной точности Ok (шесть значащих цифр!) 2) Ok 3) Ok 4) Ok ? VAL("34!5.1") ? VAL("3456789!.7") ? VAL("!1") ·34 ·3456790 ·0 Ok Ok Ok И наконец, парочка патологических случаев: 5) Ok 6) Ok ? VAL("&") ? VAL("&H") Syntax error 0 Ok Ok Таким образом, функция VAL позволяет выделить цифры, входящие в значе- ние строкового выражения, и образовать из них число для последующей мате- матической обработки. IV.1.4. STR$ - ф у н к ц и я Часто бывает необходимо осуществить преобразование числа в цифровую строку, например, число 1234.56 преобразовать в цифровую строку"1234.56". Это преобразование осуществляет функция STR$, общий вид которой: STR$(α) где: STR ("convert to STRing"-"преобразовать в строку") - служебное слово; α -арифметическое выражение. Данная функция преобразует значение арифметического выражения α в циф- ровую строку, что позволяет выделять и обрабатывать каждый символ (цифру) полученной строки с помощью с т р о к о в ы х (!) функций. П р и м е р ы: ───────────── 1) Ok 2) Ok 3) Ok print STR$(-15) print STR$(1/3) ? STR$(1.E-3) -15 ·.33333333333333 ·1E-03 Ok Ok Ok 4) Ok ? STR$(&b111);STR$(&o23);STR$(&HF1) ·7·19·241 Ok Обратите о с о б о е внимание на следующие примеры (первый символ в получаемых цифровых строках зарезервирован для указания знака числа): 5) Оk 6) Ok ? LEN(STR$(20)) ? LEN(STR$(-56.20)) 3 5 Ok Ok 7) Оk 8) Ok ? LEN(STR$(-5620)) ? LEN(STR$(1.2E-27) 5 8 Ok Ok Еще один пример использования функции STR$: оператор PRINT n;"X" выводит на экран дисплея пробел между последней цифрой значения арифмети- ческого выражения n и символом "X". Для исключения этого пробела восполь- зуйтесь оператором PRINT STR$(n);"X" 9) NEW 10) NEW Ok Ok 10 INPUT N 10 INPUT N 20 PRINT N;"i" 20 PRINT "i";n 30 ? STR$(N);"i" 30 ?"i";MID$(STR$(N),2) run run ? 10 ? 10 10 i i 10 10i i10 Ok Ok (о строковой функции MID$() см. в разделе IV.2.1.). Отметим, что обычно в программах функции VAL() и STR$() используются совместно. 11) Ok input N$:print STR$(VAL(N$)) ? 23123.45 ? -4.7 ? &HFF однако... ? 12ABBA ·23123.45 -4.7 ·255 ·12 Ok Ok Ok Ok 12) Ok input N:print VAL(STR$(N)) ? 12 ? -14.6E-2 ? &b111 ? &o21 ? &h1E ·12 -.146 ·7 ·17 ·30 Ok Ok Ok Ok Ok 13) найдите натуральные числа, не превосходящие заданного N и равные сумме кубов своих цифр. NEW Ok 10 INPUT N 20 FOR I=1 TO N 30 A$=STR$(I):S=0 40 FOR J=2 TO LEN(A$) 50 S=S+VAL(MID$(A$,J,1))^3 60 NEXT J 70 IF S=I THEN PRINTI;:NEXT I ELSE NEXT I run ? 400 ·1··153··370··371 Ok 14) определите наибольшую из цифр, используемых в десятичной записи на- турального числа M. NEW Ok 10 INPUT I 20 A$=STR$(I) 30 M=VAL(MID$(A$,2,1)) 40 FOR J=2 TO LEN(A$)-1 50 IFMA THEN A=VAL (MID$(N$,I,1)):NEXTI ELSE ELSE NEXTJ:NEXTI 60 PRINT A run run ? 1234245 ? 1243.67E34 4 7 Ok Ok Последний результат вызывает удивление, не правда ли? Однако... print n$ 1.24367E+37 Ok и все становится ясным! IV.1.5. ASC - ф у н к ц и я Напомним,что при вводе в ЭВМ символы преобразуются в соответствии с ко- дом ASCII (см. раздел I.7.3.). Функция ASC(α) где: ASC("ASC"-"American Standard Code") - служебное слово; α - строковое выражение, дает возможность установить десятичный код ASCII первого символа значения строкового выражения α. Результатом функции ASC является целое число из отрезка [0,255] (говорят, что функция ASC в о з в р а щ а е т целое чис- ло из отрезка [0,255]). П р и м е р. NEW ─────────── Ok 10 INPUT X$:Y=ASC(X$):PRINT X$;Y run run run run run ? π ? αδβ ? ; ? "," ? ♪ ◀─ символ, π 163 αδβ 160 ; 59 , 44 ♪ 1 имеющий Ok Ok Ok Ok Ok двойной код Из приведенного примера ясно, что символ "π", например, имеет десятич- ный код 163,а символ "α"(первый символ значения строковой константы"αδβ") - десятичный код 160. Далее,если значением строкового выражения α является пустая строка(""), то фиксируется ошибка "Illegal function call" . Используя предыдущий пример,попытаемся получить код символа "(кавычка). run ? " Illegal function call in 10 Ok Неудача!... Попытаемся еще разок... run ? """ ? Redo from start ? █ и т.д. Снова неудача! Не волнуйтесь, код символа "кавычка" можно получить кос- венным путем с помощью функции преобразования CHR$. IV.1.6. CHR$ - ф у н к ц и я Общий вид функции: CHR$(α) где: CHR("CHaRacter"-"символ") - служебное слово; α - арифметическое выражение. Вначале компьютер вычисляет к о д - целую часть значения выражения α. Код должен принадлежать отрезку [0,255], иначе на экране появится сообще- ние об ошибке: "Illegal function call" . Результатом функции CHR$ является однобайтовая строка, содержащая сим- вол, соответствующий полученному коду (говорят, что функция CHR$ в о з - в р а щ а е т однобайтовую строку, содержащую символ, соответствующий полученному коду). П р и м е р ы: ───────────── 1) INPUT X:Y$=CHR$(X):PRINT X;Y$ ? 34 ? 187 ? 163 34 " 187 √ 163 π Ok Ok Ok 2) переменной A$ присвоить значение "A$="BANSAJ!"" A$="A$="+CHR$(34)+"BANSAJ!"+CHR$(34) А теперь... print A$ A$="BANSAJ!" Ok 3) вывести на экран дисплея текст: "Нажмите клавишу "SHIFT"+"1". Ok PRINT "Нажмите клавишу ";CHR$(34);"SHIFT";CHR$(34);"+";CHR$(34) ;"1";CHR$(34) Нажмите клавишу "SHIFT"+"1" Ok 4) инициализация строкового массива B$(N) "псевдослучайными" словами. Ok 20 Z=RND(-TIME) 30 INPUT "Введите наибольшее количество символов слова";G 40 INPUT"Введите количество слов";N:DIM B$(N) 60 FOR K=1 TO N:A=INT((G+1)*RND(1)) 80 FOR I=1 TO A:B$(K)=B$(K)+CHR$(INT(255*RND(1))) 100 NEXT I,K 110 FOR K=1 TO N:PRINT K;"слово: ";B$(K):NEXT run Введите наибольшее количество символов слова? 4 Введите количество слов? 2 1 слово: ▲щΓ 2 слово: X∞p Ok Функции ASC() и CHR$() являются взаимообратными, то есть X=ASC(CHR$(X)) и Y$=CHR$(ASC(Y$)), если только значение арифметического выражения X находится в допустимых пределах (напомним, что 0≤X≤255!), а LEN(Y$)=1. 5) присвоить строковой переменной Y$ значение "yes", если X≥1 и "no" - если X<1. Оператор условного перехода IF...THEN...ELSE... не применять! NEW Ok 10 INPUT X 20 Y$=CHR$(-(X>=1)*ASC("y"))+CHR$(-(X>=1)*ASC("e"))+CHR$(-(X>=1)*ASC(" s"))+CHR$(-(X<1)*ASC("n"))+CHR$(-(X<1)*ASC("o")):print Y$ run run ? 5 ? -1 yes no Ok Ok Наконец заметим, что функцию CHR$ удобно использовать для работы с не- печатаемыми "символами" (BS, SELECT, RETURN, клавиши управления курсором). IV.1.7. BIN$ - ф у н к ц и я BIN$-функция применяется для преобразования целого числа в двоичную символьную строку. Ее общий вид: BIN$(α) где: BIN ("BINary"-"двоичный") - служебное слово; α - арифметическое выражение. Вначале вычисляется значение арифметического выражения α; результат преобразуется в целое число (возможно со знаком); если это число не попа- дает на отрезок [-32768,65535],то компьютер фиксирует ошибку переполнения "Overflow" . Полученное число записывается в двоичной системе счисления, а затем прео- бразуется в символьную строку, соответствующую его двоичному коду. Таким образом, Ok Ok Ok ? BIN$(3),BIN$(0) ? BIN$(32767) ? BIN$(65536) 11············0 111111111111111 Overflow Ok Ok Ok Максимальная длина строки результата функции BIN$() - 16. Обозначим целую часть значения выражения α буквой N. Заметим, что для отрицательных N компьютер вычисляет значение функции BIN$(N) по рекуррентной формуле: BIN$(N) = BIN$(65536+N) . П р и м е р ы: ───────────── 1) BIN$(-1) возвращает "1111111111111111", BIN$(-32768) возвращает "1000000000000000", BIN$(32768) возвращает "1000000000000000", BIN$(65535) возвращает "1111111111111111". 2) print VAL("&B"+BIN$(15)) 15 Ok Наконец, при помощи функции BIN$ можно "научить" компьютер двоичной арифметике. Посмотрите, например, как работает следующая программа: 3) Ok 10 PRINT"Могу найти сумму двух двоичных чисел!" 20 INPUT "Первое число, второе число";N1$,N2$ 40 ANS=VAL("&B"+N1$)+VAL("&B"+N2$) 50 BN$=RIGHT$(STRING$(16,"0")+BIN$(ANS),16)'См.аналогию в п. 1.9! 60 PRINT"Ответом является:";BN$;" или";ANS;"десятичное" run Могу найти сумму двух двоичных чисел! Первое число, второе число? 1111111111111111,1 Ответом является:0000000000000000 или 0 десятичное Ok Неизвестные Вам пока строковые функции RIGHT$ и STRING$ рассмотрены ни- же в разделах IV.2.3. и IV.2.4. 4) среди простых чисел, не превосходящих N , найти такое, в двоичной записи которого максимальное число единиц. NEW Ok 10 INPUT N 20 FOR I=1 TO N:FOR J=2 TO INT(SQR(I)) 40 IF IMODJ=0 GOTO 100 ELSE NEXT J 50 M$=BIN$(I):PRINT I;M$:L=0 60 FOR K=1 TO LEN(M$):IF MID$(M$,K,1)="1" THEN L=L+1 80 NEXTK 90 IF L>R THEN R=L:R1=I 100 NEXT I 110 PRINT R;R1 run ? 18 1 1 ·7·111 ·17·10001 3 11 ·11·1011 ·3··7 5 101 ·13·1101 Ok 5) выделить старший и младший байты двоичного числа A% NEW Ok 10 INPUT"Введите число A% (не более 16 двоичных цифр)";A% 20 IF A%<0 THEN H%=A%\256-1 ELSE H%=A%\256 25 L%=A%MOD256 30 PRINT RIGHT$("00000000"+BIN$(H%),8);" ";RIGHT$("00000000"+BIN$(L%), 8) run Введите число А% (не более 16 двоичных цифр)? &B1011110001010011 10111100 01010011 ▲ Ok │ число отрицательное! run Введите число А% (не более 16 двоичных цифр)? &B0011110001010000 00111100 01010000 ▲ Ok │ число положительное! IV.1.8. OCT$ - ф у н к ц и я OCT$-функция служит для преобразования числа в восьмеричную символьную строку. Ее общий вид: OCT$(α) где: OCT ("OCTal-"-"восьмеричный-") - служебное слово; α - арифметическое выражение. Эта функция вычисляет значение арифметического выражения α, преобразу- ет результат в целое (возможно со знаком); если результат не принадлежит отрезку [-32768,65535], то фиксируется ошибка: "Overflow" ("П е р е п о л н е н и е"). В противном случае результат преобразуется в символьную строку, представ- ляющую его значение в восьмеричной системе счисления. Максимальная длина строки-результата OCT$() - 6 символов (6 байтов). П р и м е р. Ok ─────────── print OCT$(&HFFFF) 177777 Ok Обозначим буквой N целую часть значения выражения α. Если N принадлежит диапазону [0,65535],то значение функции OCT$() нахо- дится компьютером без обращения к дополнительному коду, например: print OCT$(0) print OCT$(65535) 0 177777 Ok Ok Если же N принадлежит диапазону [-32768,-1],то значение функции OCT$() находится ЭВМ с использованием дополнительного кода, т.е. по рекуррентной формуле OCT$(N)=OCT$(65536+N) Например: 1) Ok 0k print OCT$(-1) сравните с print OCT$(65535) 177777 177777 Ok Ok 2) Ok Оk ? OCT$(-32768) сравните с print OCT$(32768) 100000 100000 Ok Ok З а д а ч а. Попытайтесь научить компьютер "восьмеричной" арифметике. ─────────── Используйте для этой цели идею следующего фрагмента: print VAL("&O"+OCT$(100)) 100 Ok И, наконец ... IV.1.9. HEX$ - ф у н к ц и я HEX$-функция служит для преобразования целого числа в шестнадцатерич- ную символьную строку. Ее общий вид: HEX$(α) где: HEX ("HEXadecimal-"-"шестнадцатеричный-") - служебное слово; α - арифметическое выражение. Вначале вычисляется N - целая часть значения арифметического выраже- ния α. Если N не попадает на отрезок [-32768,65535], то компьютер сообща- ет об ошибке: "Overflow" ("П е р е п о л н е н и е"). "Правильное" N преобразуется в символьную строку, соответствующую его шестнадцатеричному коду. Максимальная длина результата вычисления значе- ния функции равна ч е т ы р е м байтам (четырем символам). Если целое число N находится на отрезке [0,65535], то преобразование элементарно: HEX$(0) возвращает "0" , HEX$(65535) возвращает "FFFF" . Однако, значение функции при отрицательных N,принадлежащих [-32768,-1], вычисляется компьютером с использованием дополнительного кода, т.е. с при- менением рекуррентной формулы: HEX$(N)=HEX$(65536+N); HEX$(-1) = HEX$(65535) возвращает "FFFF"; HEX$(-32768) = HEX$(32768) возвращает "8000". Функция VAL() в комбинации с функцией HEX$() позволяют получить обрат- ное преобразование: N=VAL("&h"+HEX$(N)) . П р и м е р ы: Ok Ok ───────────── ? VAL("&h"+HEX$(3)) ? VAL("&H"+HEX$(-10)) 3 -10 Ok Ok Существование функции HEX$() делает возможным "обучение" компьютера шестнадцатеричной арифметике. Единственная трудность состоит в добавлении к числу нулей, стоящих в старших разрядах (если, конечно,это необходимо!). Подумайте!... Придумали? Если нет, то возьмите на вооружение следующий красивый прием: X$=RIGHT$("0000"+HEX$(N),4) или X$=RIGHT$(STRING$(4,"0")+HEX$(N),4). П р и м е р. ─────────── 1) NEW Ok 10 PRINT"Введите два шестнадцатеричных числа" 20 INPUT A$,B$ 30 SM=VAL("&H"+A$)+VAL("&H"+B$) 40 DF=VAL("&H"+A$)-VAL("&H"+B$) 50 PRINT "Сумма, разность:";RIGHT$("0000"+HEX$(SM),4);SPC(1);RIGHT$ ("0000"+HEX$(DF),4) run run Введите два числа Введите два числа ? 1,1 ? FFFF,FFFF Сумма, разность:0002 0000 Сумма, разность:FFFE 0000 Ok Ok run run Введите два числа Введите два числа ? F000,FFF1 ? FFFFF,E Сумма, разность:EFF1 F00F Overflow in 30 Ok Ok 2) выделить старший и младший байты шестнадцатеричного числа A% . NEW Ok 10 INPUT "Введите число А% (не более 4 шестнадцатеричных цифр)";A% 20 IF A%<0 THEN H%=A%\256-1 ELSE H%=A%\256 25 L%=A%MOD256 30 PRINT RIGHT$("00"+HEX$(H%),2);" ";RIGHT$("00"+HEX$(L%),2) run Введите число А% (не более 4 шестнадцатеричных цифр)? &H67EA 67 EA ───▲── Ok положительное число┘ run Введите число А% (не более 4 шестнадцатеричных цифр)? &HE2A9 E2 A9 ───▲── Ok отрицательное число┘ Теперь настало время подумать,почему встроенные функции,изученные нами в разделах IV.1.1 - IV.1.9, называются "функциями преобразования". IV.2. ВСТРОЕННЫЕ СТРОКОВЫЕ ФУНКЦИИ Пока слепо плыл сон по разбитым надеждам, Космос с болью сочился над разбитой любовью, Был из скрытных людей свет твой медленно изгнан, И небо не спало. Избранные стихотворения компьютера RCA-301, поэма 929 В этом разделе мы рассмотрим следующие встроенные функции: MID$, LEFT$, RIGHT$, STRING$, SPACE$. IV.2.1. MID$ - ф у н к ц и я Oбщий вид MID$ - функции следующий: MID$(α,m[,n]) где: MID ("MIDdle"-"середина") - служебное слово; α - строковое выражение; m, n - арифметические выражения, целые части значений которых должны принадлежать отрезку [1,255]. Напомним, что квадратные скобки,встречающиеся при описании синтаксиса,- обозначение, указывающее, что элемент синтаксической конструкции внутри них не является обязательным. Условимся целые части значений арифметических выражений m и n обозна- чать соответственно M и N. По умолчанию N равно количеству символов значения строкового выражения α от позиции M и до конца строки включительно. Рассмотрим два возможных случая. 1. Функция MID$ с л е в а от знака равенства в операторе присваива- ния LET. ┌───────────────────────────────────┐ │ [LET] MID$(α,m[,n]) = β │ └───────────────────────────────────┘ Здесь β - строковое выражение. Пусть L - длина значения строкового выражения β.При выполнении операто- ра LET символы значения строкового выражения α, начиная с позиции M, по- следовательно замещаются на первые min(L,N) символов строкового выражения β. Остальные символы значения строкового вы- ражения α остаются без изменений (см. рис.1). 1-й 2-й М-й (М+1)-й (M+N-1)-й LEN(α)-й символ символ символ символ символ символ │ │ │ │ │ │ ┌───▼───┬───▼───┬───┬───▼───┬───▼───┬───┬───▼───┬───┬───▼───┐ │ │ │...│███████│███████│...│███████│...│ │ α └───────┴───────┴───┴───────┴───────┴───┴───────┴───┴───────┘ │◀─────── N символов ──────▶│ ▲ ▲ │ │ ┌───────────────────────────┐ │ MID$(α,M,N) = β │ ▲───────────────────────────▲ │ │ ┌────────────────────────────────────────┐ L > N │███████│███████│...│███████│ ...│███████│ β └────────────────────────────────────────┘ │◀──────────────── L символов ──────────▶│ или ▲ ▲ │ │ ┌───────────────────┐─ ─ ─ ─┐ L < N │███████│...│███████│ │β └───────────────────┘─ ─▲─ ─┘ │◀─── L символов───▶│ │ символы из α Р и с. 1 П р и м е р. ─────────── 10 X$="12345678910":INPUT Y$,M,N:MID$(X$,M,N)=Y$:PRINT X$ run ┌────────────────┐ run ┌────────────────┐ ? стол,8,4 │X$="12345678910"│ ? стул,1,4 │X$="12345678910"│ 1234567стол │ └──┘ │ стул5678910 │ └──┘ │ Ok │ Y$="стол"│ Ок │Y$="стул" │ └────────────────┘ └────────────────┘ run ┌────────────────┐ run ┌────────────────┐ ? сто,8,3 │X$="12345678910"│ ? казак,8,5 │X$="12345678910"│ 1234567сто0 │ └─┘ │ 1234567каза │ └──┘ │ Ok │ Y$="сто" │ Ok │ Y$="каза"│ └────────────────┘ └────────────────┘ И наконец, вместо оператора присваивания вида А$ = строковое выражение , используйте оператор: MID$(А$,1) = строковое выражение , чтобы избежать использования дополнительной памяти. Но учтите, что строко- вая переменная A$ уже должна существовать и LEN(A$)≥LEN(строковое выражение) ! 2. Функция MID$ с п р а в а от знака равенства в операторе присваи- вания LET. ┌─────────────────────────────────────┐ │ [LET] γ = MID$(α,m[,n]) │ └─────────────────────────────────────┘ Здесь γ - строковая переменная. При выполнении указанной конструкции N последовательных символов значе- ния α, начиная с позиции M, становятся значением строковой переменной γ. Предварительное определение γ не обязательно (см. рис.2). 1-й 2-й М-й (М+1)-й (М+N-1)-й LEN(α)-й символ символ символ символ символ символ │ │ │ │ │ │ ┌───▼───┬───▼───┬───┬───▼───┬───▼───┬───┬───▼───┬───┬───▼───┐ │ │ │...│███████│███████│...│███████│...│ │ α └───────┴───────┴───┴───────┴───────┴───┴───────┴───┴───────┘ │ ┌─────────────────┐ │ │ │ γ = MID$(α,M,N) │ │ │ └─────────────────┘ │ ▼───────┬───────┬───┬───────▼ │███████│███████│...│███████│ γ └───────┴───────┴───┴───────┘ │◀────── N символов────────▶│ Р и с. 2 П р и м е р ы: ───────────── 1) Ok 2) Ok ? MID$("КЛАВИАТУРА",3,4) ? MID$("капрал"+"литр",4,5) АВИА └──┘ ралли └──────┘ Ok Ok 3) Ok 4) Ok ? MID$("молоко"+"брат",5,5) ? MID$("СОР У НОР",3,5) кобра └──────┘ Р У Н └───┘ Ok Ok 5) Ok 6) NEW 10 input I,J:? MID$("234",I,J) Ok run run run run 1 Z$="123" ? 1,1 ? 2,90 ? 10,1 ? 1,0 2 INPUT X$,M 2 34 3 Z$=MID$(X$,M) Ok Ok Ok Ok 4 Y$=MID$(X$,M+4) run или run 5 PRINT Z$ ? -1,1 ? 0,0 6 PRINT Y$ Illegal function call in 10 run Ok ? Баба-Яга-костяная нога,6 run или run Яга-костяная нога ? 2,-1 ? 0,1 костяная нога Illegal function call in 10 Ok Ok 7) определить третий символ в слове X$. Ok input x$:z$=mid$(x$,3,1):print z$ ? интеграл т Ok Если требуется определить K-й символ в слове X$, то программа будет иметь следующий вид (разумеется, 1≤K≤LEN(X$)): NEW Ok 10 INPUT X$,K 20 IF K<1 OR K>LEN(X$) THEN PRINT"Буквы с указанным номером в слове не т":END ELSE Z$=MID$(X$,K,1):PRINT Z$:END run run ? информатика,3 ? информатика,12 ф Буквы с указанным номером в слове нет Оk Ok П р и м е р 8. Для получения числа, состоящего из двух младших цифр це- ───────────── лого числа N, воспользуйтесь строкой: 10 X%=VAL(MID$(STR$(N),LEN(STR$(N))-1,2)) Заметим,что Вы можете выполнить то же самое,используя функцию INT(): 10 INPUT N:PRINT N-INT(N/100)*100 П р и м е р 9. Написать программу, определяющую, сколько раз слово Z$ ───────────── встречается в слове X$. NEW Оk 10 INPUT X$,Z$:J=0 20 FOR I=1 TO LEN(X$)-LEN(Z$)+1 30 IF Z$<>MID$(X$,I,LEN(Z$)) THEN NEXTI ELSE J=J+1:NEXTI 40 PRINT J:END run ? БАОБАБ,БА 2 Ok П р и м е р 10. Написать программу, заменяющую в слове X$ слово Z$ на ────────────── слово Y$ той же длины. NEW Оk 10 INPUT X$,Z$,Y$:IF LEN(Z$)>MID$(X$,J,LEN(Z$)) THEN 50 40 MID$(X$,J,LEN(Y$))=Y$ 50 NEXT J:PRINT X$:END run ? ДОМ КИРПИЧНЫЙ ?? КИРПИЧНЫЙ ?? БАНАНОВЫЙ ДОМ БАНАНОВЫЙ Оk Косо лети же, житель осок. Я разуму уму заря, Мечтатель! Летать чем? В.Хлебников Я иду с мечом судия. С.Кирсанов Г.Р.Державин П р и м е р 11. Слова и фразы,переходящие в себя при "акустическом ото- ────────────── бражении", получили название п а л и н д р о м о в. Это слово греческого происхождения и означает "движущийся обратно", "обра- тимый". Найти палиндром практически невозможно, но его нетрудно построить. В качестве "строительных блоков" простейших палиндромов следует выбирать слова, не изменяющиеся при чтении от конца к началу. Выдерживают отраже- ние в "акустическом зеркале" такие слова, как боб, дед, кок, мим, иди, то- пот, потоп, колок, ротор, кабак, моном и выражения, такие, например,как "Леша на полке клопа нашел". Ok 10 INPUT X$:Y$="" 20 FOR I=1 TO LEN(X$):Y$=MID$(X$,I,1)+Y$:NEXT 30 IF X$=Y$ THEN PRINT"Палиндром!" ELSE PRINT"Не палиндром!" run run run ? косолетижежителосок ? мечтателлетатчем ? я разуму уму заря Палиндром! Палиндром! Не палиндром! Ok Ok Ok Сравните результат действия функции MID$(A$,I,J),стоящей справа от зна- ка равенства в операторе присваивания, с результатом операции в ы р е з- к и: A[i:i+j-1] , где: А - текст; i - номер первого символа фрагмента,вырезаемого из текста A; j - количество символов в фрагменте,вырезаемом из текста A, в школьном алгоритмическом языке. Рассмотрите интересный часто встречающийся частный случай j=1, т.е.про- ведите аналогию между MID$(A$,I,1) и A[i:i]. И, наконец, сопоставьте результат действия функции MID$, стоящей слева от знака равенства в операторе присваивания, с результатом работы команды частичного изменения значения литерной величины (команды присваивания вы- резке) A[i:j]=B , позволяющей заменить часть слова А,начинающуюся с i-той буквы и оканчиваю- щуюся j-той буквой, на слово B, в школьном алгоритмическом языке. IV.2.2. LEFT$ - ф у н к ц и я Общий вид функции: LEFT$(α,n) где: LEFT ("left"-"левый") - служебное слово; α - строковое выражение; n - арифметическое выражение, целая часть значения которого должна принадлежать отрезку [0,255]. Функция LEFT$ позволяет выделить самые л е в ы е n символов значения строкового выражения α . LEFT$ - функция является"частным случаем" MID$- функции и через нее мо- жет быть определена так: LEFT$(α,n) = MID$(α,1,n) . П р и м е р ы: ───────────── 1) Ok 3) Ok 10 INPUT X$,N ? LEFT$("деньги",4) 20 U$=MID$(X$,1,N) день └──┘ 30 V$=LEFT$(X$,N) Ok 40 PRINT U$;V$ 4) Ok run ? LEFT$("abc",2);LEFT$(LEFT$ ? 1234567890,6 ("def",2),1) 123456123456 abd Ok Ok 2) Ok 5) Ok ? LEFT$("деньги",0) ? LEFT$("wap",-1) Illegal function call Ok Ok IV.2.3. RIGHT$ - ф у н к ц и я Общий вид функции: RIGHT$(α,n) где: RIGHT ("right"-"правый") - служебное слово; α - строковое выражение; n - арифметическое выражение, целая часть значения которого должна принадлежать отрезку [0,255]. Функция RIGHT$ позволяет выделить самые п р а в ы е n символов зна- чения строкового выражения α (в этом смысле функция RIGHT$() симметрич- на функции LEFT$()!). RIGHT$ - функция является частным случаем MID$ -функции и через нее мо- жет быть определена так: RIGHT$(α,n) = MID$(α,L-n+1,n) где L - длина значения строкового выражения α. П р и м е р ы: ───────────── 1) Ok 2) Ok ? RIGHT$("abcdgoldfish",8) ? RIGHT$("гамбит",3) goldfish └──────┘ бит └─┘ Ok Ok 3) Ok 4) Ok 10 INPUT X$,N ? RIGHT$(LEFT$("рубa 20 U$=MID$(X$,LEN(X$)-N+1) йте!",6),4) 30 V$=RIGHT$(X$,N):? U$;V$ байт run Ok ? 1234567890,4 5) ? MID$("рубайте!",3,4) 78907890 байт └──┘ Ok Ok Заметим, что хотя функции LEFT$ и RIGHT$ являются "частными случаями" функции MID$, их нельзя использовать с л е в а от символа присваивания в операторе LET! Посмотрите... NEW Ok 1 A$="Барсик":MID$(A$,1,4)="Корт":PRINT A$ 2 B$="Комик":LEFT$(B$,3)="Том":PRINT B$ run Кортик Syntax error in 2 Ok П р и м е р 6. Образовать слово Y$, состоящее из первых N и последних ───────────── К символов данного слова Х$. Первоначальный вариант программы выглядит так: NEW Ok 10 INPUT X$,N,K 20 Y$=LEFT$(X$,N)+RIGHT$(X$,K) 30 PRINT "Результат:";Y$ 40 END run run run ? аллигатор,3,6 ? аллигатор,0,6 ? аллигатор,0,0 Результат:аллигатор Результат:игатор Результат: Ok Ok Ok однако ... run ? аллигатор,-4,3 Illegal function call in 20 Ok Поэтому дополним программу строкой: 15 IF N<0 OR N>LEN(X$) OR K<0 OR K>LEN(X$) THEN PRINT"Не балуйтесь! По вторите!":GOTO 10 Выполним полученную программу: run run ? аллигатор,9,10 ? аллигатор,-1,5 Не балуйтесь! Повторите! Не балуйтесь! Повторите! ? аллигатор,6,0 ? аллигатор,9,10 Результат:аллига Не балуйтесь! Повторите! Оk ? Строка 15 обеспечивает повторный запрос на ввод исходных данных в том случае, когда K<0 или К> длины слова Х$, или N<0, или N>длины слова X$ (своеобразная "защита"программы от непредусмотренной исходной информации). П р и м е р 7. Написать программу перевода чисел, записанных римскими ───────────── цифрами, в числа, записанные арабскими цифрами. NEW Ok 1 DATA 1000,M,900,CM,500,D,400,CD,100,C,90,XC,50,L,40,XL,10,X,9,IX,5,V ,4,IV,1,I:INPUT"N$";N$ 2 READ A,A$ 3 IF A$=LEFT$(N$,LEN(A$)) THEN N$=RIGHT$(N$,LEN(N$)-LEN(A$)):N=N+A:GOT O 3 4 IF N$>" "GOTO 2 5 PRINT N run run run run run N$? IV N$? CMIV N$? MMMDXCLLI N$? MCMXVII N$? MDCCCXII 4 904 3691 1917 1812 Ok Ok Ok Ok Ok А как насчет программы обратного перевода? Пожалуйста! П р и м е р 8. Написать программу перевода чисел, записанных арабскими ───────────── цифрами, в числа, записанные римскими цифрами. NEW Ok 1 DATA 1000,M,900,CM,500,D,400,CD,100,C,90,XC,50,L,40,XL,10,X,9,IX,5,V, 4,IV,1,I:INPUT"N";N 2 READ A,A$ 3 IF A<=N THEN PRINT A$;:N=N-A:GOTO 3 4 IF N>0 GOTO 2 run run run run N? 654 N? 25 N? 11111 N?3691 DCLIV XXV MMMMMMMMMMMCXI MMMDCXCI Ok Ok Ok Ok IV.2.4. STRING$ - ф у н к ц и я Общий вид STRING$ -функции следующий: STRING$(n,α) или STRING$(n,m) , где: STRING ("string"-"строка") - служебное слово; α - строковое выражение; n,m - арифметические выражения, целые части значений которых должны принадлежать отрезку [0,255]. Обозначим N-значение арифметического выражения n. Тогда,в случае форма- та STRING$(n,α) функция возвращает строку,состоящую из N одинаковых симво- лов, равных первому символу значения строкового выражения α. А в случае формата STRING$(n,m) значением функции является последова- тельность N одинаковых символов, код ASCII которых одинаков (ведь симво- лы одинаковы!) и равен целой части значения арифметического выражения m. Поэтому, если Вы хотите инициализировать строковую переменную A$, N п р о б е л a м и (наиболее часто встречающаяся операция!), то два приве- денных ниже оператора выполняют идентичное действие: A$=STRING$(N,32) , A$=STRING$(N," ") (ведь CHR$(32)=" "!). Таким образом, с помощью STRING$ - функции можно назначать длину и про- водить инициализацию строковых переменных пробелами. Приведем несколько тривиальных примеров: 1) Ok Y$=STRING$(10,"*"):? LEN(Y$):? "#"+Y$+"FILE" 10 #**********FILE Ok 2) Ok print STRING$(10,52);STRING$(10,CHR$(52)) 44444444444444444444 Ok 3) Ok A$=STRING$(5," "):MID$(A$,3,3)="Все!":? A$ ··Все Ok Если n=0, то функция STRING$ возвращает пустую строку (""), независимо от того, какие α или m Вы задали. В тех случаях, когда целые части значений арифметических выражений n и m находятся вне отрезка [0,255],на экране дисплея появляется сообщение об ошибке: "Illegal function call" ("Н е д о п у с т и м ы й в ы з о в ф у н к ц и и"). IV.2.5. SPACE$ - ф у н к ц и я Общий вид функции: SPACE$(n) где: SPACE ("space"-"пространство") - служебное слово; n - арифметическое выражение, целая часть значения которого должна принадлежать отрезку [0,255]. С помощью SPACE$-функции назначается длина и проводится начальная ини- циализация пробелами строковых переменных. Например, если Вы хотите иници- ализировать новую строковую переменную X$ N пробелами, то используйте опе- ратор присваивания X$=SPACE$(N) SPACE$-функция является частным случаем STRING$-функции и через нее мо- жет быть определена так: SPACE$(n)=STRING$(n," ") IV.2.6. П р и м е р ы 1) выделить из текста,являющегося значением строковой переменной T$,от- дельные слова (они отделены друг от друга одним пробелом) и записать их в строковый массив с именем W$. (Психологи утверждают, что из минуты, за- траченной на чтение, мы 58 секунд считываем промежутки между символами!) NEW Ok 10 LINEINPUT T$:T$=T$+" ":K=0'K-количество слов в T$ 20 FOR I=1 TO LEN(T$):IF MID$(T$,I,1)=" " THEN K=K+1 35 NEXT I 'Количество слов в Т$ найдено! 40 DIM W$(K):DIM P(K)'Вот теперь можно описать массивы! 45 FOR J=1 TO K:W$(J)=SPACE$(5):NEXTJ 'Начальная инициализация пробела ми элементов массива W$(K) 47 N=1:FOR J=1 TO K:FOR I=N TO LEN(T$) 70 IF MID$(T$,I,1)=" " GOTO 85 80 NEXT I 85 P(J)=I:W$(J-1)=MID$(T$,N,P(J)-P(J-1)-1):N=P(J)+1:PRINT W$(J-1);SPC(5) 90 NEXT J run 123 4 567 123·····4·····567 Ok Елечвок енмяет ослог. А.Вознесенский. Человек 2) даны два слова X$ и Y$. Проверить, можно ли из символов, входящих в слово X$, составить слово Y$. Символы можно переставлять, и каждый символ можно использовать несколько раз! NEW Ok 10 INPUT X$,Y$ 30 FOR I=1 TO LEN(Y$):FOR J=1 TO LEN(X$) 50 IF MID$(Y$,I,1)=MID$(X$,J,1) THEN A$="да":NEXT I ELSE A $="нет":NEXT J 80 PRINT A$:END run run ? школаа,алокша ? AB,BB да да Ok Ok 3) даны два натуральных числа M и N.Проверьте,можно ли из цифр числа M составить число N. Цифры можно переставлять и использовать: a) более одно- го раза; b) не более одного раза. a) NEW Ok 10 INPUT M,N:M$=STR$(M):N$=STR$(N) 30 FOR I=2 TO LEN(N$):FOR J=2 TO LEN(M$) 40 IF MID$(N$,I,1)<>MID$(M$,J,1) THEN NEXT J:?"Нельзя!"ELSE NEXTI: ?"Можно!" run run run ? 6785,58758 ? 6785,58358 ? 6785,87 Можно! Нельзя! Можно! Ok Ok Ok b) NEW Ok 10 INPUT M,N:X$=" ":M$=STR$(M):N$=STR$(N) 40 FOR I=2 TO LEN(N$):FOR J=2 TO LEN(M$) 50 IF MID$(N$,I,1)=MID$(M$,J,1) THEN MID$(N$,I,1)=X$:MID$(M$,J,1)= X$:NEXTI:?"Можно!" ELSE NEXTJ:?"Нельзя!" run run ? 12345432,1236 ? 1234554320,1022 Нельзя! Можно! Ok Ok 4) число 41 обладает следующим свойством: 41²=1681,√16=4 и √81=9, т.е. числа 16 и 81 - точные квадраты; найти все натуральные числа, не превосхо- дящие N,и такие, что первые две и последние две цифры квадрата числа явля- ются точными квадратами. NEW Ok 10 INPUT"Сколько чисел необходимо проверить";N:PRINT"Интересующие Вас числа:"; 20 FOR I=10 TO N:B=I^2 40 B$=MID$(STR$(B),2):IF VAL(RIGHT$(B$,2))<>0 THEN 50 ELSE NEXT I: END 50 IF SQR(VAL(LEFT$(B$,2)))=FIX(SQR(VAL(LEFT$(B$,2)))) AND SQR(VAL(RIG HT$(B$,2)))=FIX(SQR(VAL(RIGHT$(B$,2))))THENPRINT I;:NEXTI ELSE NEXTI run Сколько чисел необходимо проверить? 100 Интересующие Вас числа: 41 Ok 5) написать программу, которая заменяет часть слова Z$ текста T$ на текст Y$ с сохранением одного пробела между словами. NEW Ok 5 PRINTSPC(8);"Вводите текст !":LINEINPUT T$:T$=T$+" ":K=0 15 INPUT "Какое слово менять";Z$ 16 INPUT "На какое слово менять";Y$ 20 FOR I=1 TO LEN(T$):IF MID$(T$,I,1)=" " THEN K=K+1:NEXTI ELSE NEXTI 'K-количество слов в тексте T$ 40 DIM W$(K):DIM P(K)'Вот теперь можно описать массивы! 45 FOR J=1 TO K:W$(J)=SPACE$(5):NEXT J 47 N=1'N-номер первой буквы текущего слова в тексте 50 FOR J=1 TO K: FOR I=N TO LEN(T$) 70 IF MID$(T$,I,1)=" " GOTO 85 80 NEXT I 84 'P()-массив,содержащий номера позиций пробелов в тексте 85 P(J)=I:W$(J-1)=MID$(T$,N,P(J)-P(J-1)-1):N=P(J)+1 90 NEXT J 95 A$="Образец не найден! Ваш текст:" 100 FOR J=0 TO K-1 105 IF W$(J)=Z$ THEN W$(J)=Y$:A$="":GOTO 120 106 FOR I=1 TO LEN(W$(J))-LEN(Z$)+1 107 IF Z$<>MID$(W$(J),I,LEN(Z$))THEN115 108 W$(J)=LEFT$(W$(J),I-1)+Y$+RIGHT$(W$(J),LEN(W$(J))-I-LEN(Z$)+1):A$= "" 115 NEXTI 120 NEXT J 130 FOR J=0 TO K-1:B$=B$+W$(J)+" ":NEXT 145 PRINT A$ 150 PRINT B$:END run ········Вводите текст ! Мама мыла Эмму Какое слово менять? мы На какое слово менять? очень люби ································· Мама очень любила Эмму Ok 6) составьте программу, в результате работы которой выяснялось бы, мож- но ли переставить цифры десятичной записи числа K так,чтобы они образовы- вали арифметическую или геометрическую прогрессию. NEW Ok 10 CLS:DIM K,M%,D%,Q,F$:INPUT"Введите нат. число";K 30 F$=STR$(K):M%=LEN(F$):DIM A(M%) 40 FOR I=1 TO M%:A(I)=VAL(MID$(F$,I,1)):NEXT 50 FOR I=2 TO M%-1:FOR J=I+1 TO M% 60 IF A(I)>A(J)THEN SWAP A(I),A(J) 70 NEXT J,I 80 D%=A(3)-A(2) 90 IF M%<3 THEN PRINT"Число должно содержать не менее 2 цифр":GOTO 20 100 IF M%=3 THEN PRINT"Арифм.прогрессия есть!":GOTO 150 110 FOR I=4TO M% 120 IF A(I)-A(I-1)<>D%THEN ?"Арифм.прогрессии нет":GOTO160 130 NEXT I 140 PRINT"Арифм.прогрессия есть!" 150 IF M%=3 AND A(3)=0 THEN PRINT"Геом.прогрессии нет":END 160 FOR I=2 TO M%:IF A(I)=0 THEN?"Геом.прогрессии нет":END 170 NEXT I 180 Q=A(3)/A(2) 190 IF M%=3 THEN ?"Геом.прогрессия есть!":END 200 FOR I=4 TO M% 210 IF A(I)/A(I-1)<>Q THEN PRINT"Геом.прогрессии нет":END 220 NEXT I 230 PRINT"Геом.прогрессия есть!":END run run Введите нат. число? 7132546 Введите нат. число? 42 Арифм.прогрессия есть! Арифм.прогрессия есть! Геом.прогрессии нет Геом.прогрессия есть! Ok Ok 7) составить программу, которая m-кратно повторяет каждый символ в сло- ве X$. NEW Ok 10 INPUT"Введите слово";X$ 20 INPUT"Укажите число повторений символов";M% 30 IF M%=0 OR M%*LEN(X$)>255 THEN ?"Повторите ввод":GOTO10 40 N$="":FOR I=1 TO LEN(X$):FOR J=1 TO M% 70 N$=N$+MID$(X$,I,1):NEXTJ,I 90 PRINT "Вы этого хотели? ";N$ run Введите слово? керпкпр Укажите число повторений символов? 2 Вы этого хотели? ккееррппккппрр Ok 8) составить программу вывода всех натуральных чисел, меньших N, сумма квадратов цифр которых равна M. NEW Ok 5 DEFINT I,J,N,M,Y:INPUT N,M 10 FOR I=1 TO N:Y=0:A$=STR$(I) 20 FOR J=2 TO LEN(A$):Y=Y+VAL(MID$(A$,J,1))^2:NEXTJ 30 IF Y=M THEN PRINTI;:NEXTI ELSE NEXTI 40 END run ? 123,65 ·18··47··74··81··108 Ok 9) по данному натуральному N найдите наименьшее из чисел, имеющих сто- лько же и таких же цифр, что и N, если известно, что каждую цифру числа N можно использовать при записи один раз. NEW Ok 10 DEFINT I,J: DEFSTR A 20 INPUT "В каком числе хотите перетрясти цифры";N 25 IF LEN(STR$(N))>14 THEN PRINT "Не озоруй!":GOTO 20 30 FOR I=0 TO9:FOR J=2 TO LEN(STR$(N)) 40 IF I=VAL(MID$(STR$(N),J,1))THEN A=A+STR$(I) 50 NEXT J,I 60 PRINT VAL(A):END run В каком числе хотите перетрясти цифры? 87655543 ·34555678 Ok run В каком числе хотите перетрясти цифры? 112235799435213 Не озоруй! В каком числе хотите перетрясти цифры? ... 10) написать программу, устанавливающую, какие из натуральных чисел,не большие заданного натурального M, делятся на каждую свою цифру. 10 DEFINT I,J,M:DEFSTR A:INPUT M 30 FOR I=1 TO M:A=STR$(I):FOR J=2 TO LEN(A) 55 IF VAL(MID$(A,J,1))=0 THEN NEXT J:NEXT I:END ELSE::::IF I MOD VAL(M ID$(A,J,1))=0 THEN NEXTJ:PRINTI;:NEXTI ELSE NEXTI run ? 40 ·1··2··3··4··5··6··7··8··9··11··12··15··22··24··33··36 Ok 11) определите,сколько цифр используется в записи натурального числа X только по одному разу. П е р в ы й способ. В т о р о й способ 10 INPUT X:X$=STR$(X) 10 INPUT"Введите число";X$ 20 K=0 20 L=LEN(X$):P=L 30 FOR J=2 TO LEN(X$) 30 FOR I=1 TO L:FOR J=1TO L 40 P=0 40 IFMID$(X$,I,1)=MID$(X$,J 50 FOR I=2 TO LEN(X$) ,1)ANDI<>J THEN P=P-1:NEXTI 60 IF MID$(X$,J,1)=MID$(X$,I,1) ELSE NEXT J,I THEN P=P+1 50 PRINT"Цифр,используемых 70 NEXTI 1 раз:";P 80 IF P=1 THEN K=K+1 run 90 NEXTJ Введите число? 12341524162 100 PRINT "K=";K Цифр,используемых 1 раз: 3 run Ok ? 45687345976 K= 3 Ok 12) из каждого слова массива C$(N) слов вычеркнуть те символы, которые употребляются при написании каждого из слов массива. NEW Ok 10 CLEAR 1500 20 INPUT"Введите количество слов";N:PRINT"Вводите слова!" 27 'В строках 30-60 идентификация исходного массива C$(N). 30 DIM C$(N):FOR I=1 TO N:INPUTC$(I):NEXT:K$="" 75 'В строках 80-130 находятся "общие" символы. Значение переменной К$ состоит из "общих" символов. 80 FOR I=1 TO N:FOR J=1 TO LEN(C$(I)):FOR R=1 TO N 110 FOR K=1 TO LEN(C$(R)) 120 IF MID$(C$(I),J,1)=MID$(C$(R),K,1) THEN NEXT R:K$=K$+MID$(C$(I),J, 1):NEXT J ELSE NEXT K,J 130 NEXT I 135 'В строках 140-180 происходит"вычеркивание"из слов массива "общих" символов. 140 FOR I=1 TO N:FOR J=1 TO LEN(C$(I)):FOR K=1 TO LEN(K$) 170 IF MID$(C$(I),J,1)=MID$(K$,K,1)THENMID$(C$(I),J,1)=" " 180 NEXT K,J,I 185 'Строки 190-230 выполняют "сжатие" слов массива C$(N),т.к.при "выч еркивании" "общих" символов образуются пробелы. 190 DIM N$(N) 200 FOR I=1 TO N:FOR J=1 TO LEN(C$(I)) 220 IF MID$(C$(I),J,1)<>" "THENN$(I)=N$(I)+MID$(C$(I),J,1) 230 NEXT J,I 240 FOR I=1TO N:PRINT"Вот";I;"слово:" ;N$(I);" - не правда ли?":NEXT run Введите количество слов? 4 Вводите слова! ? апро ? ажип ? сонп ? портфель Вот 1 слово:аро - не правда ли? Вот 2 слово:ажи - не правда ли? Вот 3 слово:сон - не правда ли? Вот 4 слово:ортфель - не правда ли? Ok 13) определить количество р а з л и ч н ы х букв,встречающихся в сло- ве A$ более одного раза. NEW Ok 10 INPUT A$:S=0 20 FOR I=1 TO LEN(A$) 30 P=0 40 FOR J=1 TO LEN(A$) 50 IF MID$(A$,I,1)=MID$(A$,J,1) THEN P=P+1 60 NEXT J 70 IF P>1 THEN S=S+1/P 80 NEXT I 90 PRINT FIX(S+.5):END run run run run aaaaaaaa ? бегемот ? Кинг-Конг ? мяучело 1 1 3 0 Ok Ok Ok Ok IV.3. ФУНКЦИИ ПОЛЬЗОВАТЕЛЯ . ОПЕРАТОР DEF FN Язык MSX-BASIC предоставляет возможность программисту (пользователю) о п р е д е л я т ь в составляемой им программе одну или несколько "соб- ственных" функций с помощью специального оператора DEF FN, имеющего следу- ющий синтаксис: DEF FNα[ (а р г у м е н т [,а р г у м е н т] ...)] = β , где: DEF FN ("FuNction DEFinition"-"определение функции")-служебные слова; α - имя переменной, для которой выделяется память; а р г у м е н т - имя переменной, для которой память не выделяется (функции пользователя могут иметь не более 9 аргументов); β - выражение, имеющее тот же тип, что и α. Итак, оператор, определяющий функцию пользователя,начинается со служеб- ного слова DEF . В идентификаторе определяемой функции два первых символа (буквы FN) являются обязательными, а остальные (α) выбираются автором про- граммы по его желанию. А р г у м е н т ы перечисляются через запятую, и вся совокупность а р г у м е н т о в заключается в круглые скобки. Отме- тим,что функция пользователя может вообще не иметь аргументов. Каждый а р г у м е н т является ф о р м а л ь н ы м параметром:это означает, что он на самом деле "не существует" (память для него не выделя- ется!) и поэтому не совпадает с переменными, имеющими такое же имя в про- грамме. Далее, после символа присваивания "=" в записи оператора, определяюще- го функцию пользователя, следует выражение β,задающее алгоритм вычисления значения функции пользователя. Это есть "образец", по которому программа каждый раз вычисляет значение функции, если,конечно,это необходимо. В вы- ражении допустим вызов любой встроенной функции и вызовы других функций пользователя. Приведем примеры о п и с а н и я функций пользователя: Ф о р м а л ь н ы е параметры │ │ │ │ ▼ ▼ ▼ ▼ 1) 10 DEF FNC(X,Y)=SQR(X+SIN(Y)) Параметры (аргументы),не являющиеся формальными │ │ ▼ ▼ 2) 30 DEF FNBUS(Z)=A*Z+B*LOG(ABS(Z))+5467.453*FNC(4,0.7) ▲ ▲ ▲ ▲ │ │ │ │ Ф о р м а л ь н ы й параметр Функция пользователя Параметр (аргумент),не являющийся формальным │ ▼ 3) 100 DEF FNQU$(QU,ST)=MID$(OL$(QU),ST) ▲ ▲ ▲ ▲ │ │ │ │ Ф о р м а л ь н ы е параметры Отметим, что р е к у р с и я з а п р е щ е н а (и прямая, и косвен- ная!). Кстати, о понятии р е к у р с и и см. в разделе IV.4 . Посмотрите... NEW Ok 10 DEF FNY(X)=(X<1)*FNY(X) 20 PRINT FNY(3) run Out of memory in 20 Ok Напомним, что и с п о л н я е м ы м оператором мы называем оператор программы, определяющий конкретные действия, которые должны быть выполнены. Оператор DEF FN может стоять в любом месте программной строки.Однако,он, в отличие от оператора DATA,- и с п о л н я е м ы й оператор, т.е. функция пользователя должна быть определена до обращения к ней. Если же обращение к функции пользователя произведено раньше ее определения оператором DEF FN, то на экране дисплея появляется сообщение об ошибке: "Undefined user function in ..." ("Функция пользователя не определена в строке ..."). Поэтому, как правило,в начале программы для операторов DEFFN специально резервируется несколько программных строк. Если в ходе выполнения программы, необходимо использовать значение функ- ции пользователя, определенной в этой программе, при заданных значениях ее аргументов, то необходимо в ы з в а т ь ее, т.е. записать идентификатор функции в соответствующее выражение, заменив формальные параметры нужными значениями аргументов - ф а к т и ч е с к и м и параметрами (константами или выражениями). Приведем примеры в ы з о в а функции пользователя: a) 50 R=FNC(3.07,5.) ▲ ▲ │ │ ф а к т и ч е с к и е параметры 3.07 и 5. b) 90 A=10:B=2:D=3.3:C=FNBUS(5*D-7) ▲ │ ф а к т и ч е с к и й параметр 5*D-7 Если выражение β содержит программные объекты (имена переменных,элемен- тов массивов, функции), описанные в качестве формальных параметров в опе- раторе DEF FN, то их значения определяются из списка фактических парамет- ров, указываемых при вызове функции пользователя. Если выражение β содержит программные объекты,не входящие в список фор- мальных параметров, то берутся их "текущие" значения из программы (на мо- мент вызова функции пользователя). В каждом из таких случаев интерпретатор обратится к описанию (опреде- лению) соответствующей функции пользователя, "подставит" вместо ф о р - м а л ь н ы х параметров необходимые значения ф а к т и ч е с к и х па- раметров и произведет требуемые вычисления, после чего результат вычисле- ния значения функции возвращается в точку вызова функции. Другими словами, компьютер выполнит над значениями фактических аргумен- тов (параметров) все те действия,которые оператор DEF FNα выполняет над своими формальными аргументами. П р и м е р ы: ───────────── 1) Ok 10 DEF FNP(X)=X^2+X+1:S=0 ▲ ▲ ▲ │ │ │ Ф о р м а л ь н ы й параметр X 20 FOR K=1 TO 7 30 S=S+FNP(K) ▲ │ Ф а к т и ч е с к и й параметр K 40 NEXT K 50 PRINT S:END run 175 Ok Ф о р м а л ь н ы й параметр X 2) NEW │ │ Ok ▼ ▼ 10 DEF FNA(X)=X*7 20 INPUT"Сколько лет Вашей собаке";D 30 PRINT"Если бы собака была человеком,ей было бы";FNA(D);"лет!" ▲ │ Ф а к т и ч е с к и й параметр D run Сколько лет Вашей собаке? 4 Если бы собака была человеком,ей было бы 28 лет! Ok Аргумент,не являющийся формальным параметром 3) NEW │ Ok ▼ 10 DEF FNZ(A,B)=A^2+B^2+C ▲ ▲ ▲ ▲ │ │ │ │ Ф о р м а л ь н ы е параметры A и B 20 INPUT X,Y,C 30 PRINT FNZ(X,Y):END ▲ ▲ │ │ Ф а к т и ч е с к и е параметры X и Y run ? 2,-3,5 18 Ok 4) NEW 5)NEW Ok Ok 10 DEF FNS$(X$,K)=MID$(X$,K,1) 10 INPUT X:IF X>1 TH 15 DEF FNQ$(X$)=FNS$(X$,K)+"$" EN DEF FNY(X)=X^2 EL 20 INPUT X$,K:PRINT FNQ$(X$):END SE DEF FNY(X)=X^3 run run 20 ? FNY(X):END ? APR,2 ? betta,4 run run P$ t$ ? 2 ? -12 Ok Ok 4 -1728 Ok Ok 6) 10 'Функция FNODD$(N) помогает проверить,является ли целое число N нечетным:если значением функции является -1, то число N - нечетное, если же значением функции является 0, то число N - четное. 20 DEF FNODD(N)=RIGHT$(BIN$(N),1)="1" Отметим, что можно определить 4 различные функции пользователя,имеющие одинаковое имя, но различающиеся по типам. 7) NEW Ok 10 DEF FNQ%=1:DEF FNQ!=2:DEF FNQ=3:DEF FNQ$="4" 20 DEFINTQ:PRINT FNQ; 30 DEFSNGQ:PRINT FNQ; 40 DEFDBLQ:PRTNT FNQ;PRINT 50 PRINT FNQ%;FNQ!;FNQ;FNQ$ run ·1··2··3 ·1··2··3·4 Ok Этот факт приводит к удивительным последствиям: например,программа мо- жет модифицировать сама себя с помощью динамического изменения вызова фун- кции (несоответствие типов формальных и фактических параметров при обраще- нии к функции пользователя ──▶ ошибка ──▶ обработка прерывания по ошибке ("ловушка" ошибки) ──▶ изменение типа функции пользователя). 8) NEW Ok 5 ON ERROR GOTO 100 10 DEF FNY(X)=X^3 15 DEF FNY$(X$)=X$+"(Козьма Прутков)" 18 DEFSTR X 20 LINEINPUT X:PRINT FNY(X):END 100 IFERR=13 THEN DEFSTR Y:RESUME0'Код 13 имеет ошибка"Type mismat ch"! run Смотри в корень! Смотри в корень!(Козьма Прутков) Ok (см. раздел VIII.3.6). Поскольку выражение β, содержащее алгоритм вычисления значения функции пользователя, хранится в памяти компьютера как ч а с т ь п р о г р а м- м ы , то DEFFN - один из нескольких операторов, которые нельзя использо- вать в режиме прямого выполнения команд (это пример о п е р а т о р а ,ко- торый не является к о м а н д о й !). 9) Ok DEF FNR(X)=X^5:PRINT FNR(2) Illegal direct Ok Сообщение об ошибке "Illegal direct" означает, что в качестве команды непосредственного выполнения встречается оператор, недопустимый в этом ре- жиме. Учтите, что если Вы допустили ошибку во время определения функции, эта ошибка будет обнаружена только тогда,когда функция встретится в выражении. Компьютер будет указывать как на источник ошибки на ту строку текста, где использована неверно заданная функция, а не на ту строку , где эта функ- ция была определена! IV.4. ПОДПРОГРАММЫ Прежде всего отметим, что п о д п р о г р а м м ы - это специальным образом оформленные группы программных строк. Подпрограммы бывают двух ти- пов: с т а н д а р т н ы е и н е с т а н д а р т н ы е . Первые из них входят в состав математического обеспечения компьютера. Нам часто приходится неявным образом обращаться к ним,когда,например, вво- дим данные в память, печатаем результаты счета, вычисляем значения встро- енных функций и т.п. Н е с т а н д а р т н ы е подпрограммы составляются самим пользовате- лем и являются фактически фрагментами его программ. В виде подпрограмм целесообразно оформлять логически завершенные части алгоритма, имеющие самостоятельную ценность; кроме того,использование под- программ позволяет экономить время и место в том случае, когда нужно в од- ной и той же программе несколько раз выполнить какую-либо последователь- ность операторов.Вместо того,чтобы многократно переписывать эту последова- тельность, напишите единственный программный м о д у л ь, к которому Вы сможете обращаться всякий раз при необходимости. Подпрограмма, следовательно, играет в какой-то степени ту же роль, что в математике "теорема" или "лемма": когда нужно доказать результат в не- которой специальной области, например, в дифференциальной геометрии,вовсе не обращаются каждый раз к базовым аксиомам теории множеств, а опираются на теоремы, которые косвенно через несколько уровней абстракции основыва- ются на этих аксиомах. Общая форма записи оператора обращения к подпрограмме (оператора вызо- ва подпрограммы) следующая: GOSUB n где: GOSUB ("GO to SUBroutine"-"идти к подпрограмме") - служебное слово; n - номер первой строки подпрограммы, 0≤n≤65529. Разумеется, нежелательно, чтобы строка с номером n находилась внутри цикла! Использование несуществующего номера программной строки n вызывает по- явление на экране дисплея сообщения об ошибке вида: "Undefined line number" ("Н е о п р е д е л е н н о м е р с т р о к и"). Подпрограмма, как правило (!), завершается оператором RETURN где RETURN ("return"-"возврат") - служебное слово. Оператор GOSUB n используется для вызова подпрограммы - группы операто- ров, начинающихся программной строкой с номером n и заканчивающихся опе- ратором RETURN. Подпрограмма может начинаться с комментария и находиться в любом месте Вашей программы. Главной особенностью оператора GOSUB является то, что оператор RETURN возвращает управление оператору,стоящему за последним выполненным операто- ром GOSUB. Заметим,что оператор, которому возвращается управление, может находиться не на следующей, а на той же программной строке! Приведем пример: Ok Ok ┌──────────────────┐ 100 X=2 100 X=2 ▼ │ 110 GOSUB 200:X=3 ┌── 110 GOSUB 200:X=3 │ 120 GOSUB 200 │ ┌ 120 GOSUB 200 │ 125 X=4 │ │ 125 X=4 ◀─ ─ ─ ─ ─ ─ ─ ─ ┐ │ 140 END │ │ 140 END │ │ 200 PRINT X^X │ │ │ │ 210 RETURN │ └─ ─ ─ ─ ─ ─ ─ ┐ │ │ run │ ▼ │ │ 4 └─────────────▶ ┌───────────────┐ │ │ 27 │ 200 PRINT X^X │ │ │ Ok │ 210 RETURN │─┘─┘ └───────────────┘ Оператор GOSUB n может показаться очень похожим на оператор GOTO n . Существенная разница между ними в том,что оператор GOSUB как бы "посылает в командировку"- после выполнения операторов подпрограммы происходит воз- вращение назад. Основная программа │ Подпрограмма ┌───────────────────┐ ▼─────────▶┌────────────┐ │ GOSUB │ │ ││ │ │ ··· │ │ ││ │ │ GOSUB │ ▼ ││ │ │ ··· │ │ ││ │ │ END │ │ ││ RETURN │ └───────────────────┘ ▼ ▼└────────────┘ В с е переменные в подпрограмме являются г л о б а л ь н ы м и. Это означает,что "доступ" к их значениям возможен из л ю б о г о места Вашей основной программы. Глобальная переменная - переменная, областью существования которой яв- ляется вся программа. Локальная переменная - переменная с ограниченной об- ластью существования в программе. Образно говоря, переменные,имеющие одно и то же имя в основной (вызыва- ющей) программе и подпрограмме не "однофамильцы", а одно и то же лицо! При вызове подпрограммы значения переменных в основной программе не"за- мораживается", а могут быть изменены операторами подпрограммы! Без "замо- раживания" то и дело происходят пренеприятнейшие вещи. Представьте себе,что Вы подарили своему товарищу очень ценную для него подпрограмму и объяснили, как ею пользоваться. Разумеется,Вашему товарищу нет никакого дела до того, какие имена переменных Вы использовали в Вашей подпрограмме. Поэтому может случиться, что и в его основной программе бу- дут использоваться переменные с теми же именами, что и в подаренной Вами подпрограмме. Ясно, что эти переменные "неразличимы" для интерпретатора. Дальнейшее ужасно! Как говорят программисты, в MSX-BASIC постоянно присутствует "побочный эффект подпрограммы"! Следовательно, важно выделить конкретные имена переменных,используемых т о л ь к о в данной подпрограмме и применить их для передачи значений аргументов из основной программы и возвращения результатов работы подпро- граммы в основную программу. Впрочем, оператор RESTORE (см. раздел II.4.5.) предоставляет возмож- ность каждой подпрограмме иметь свои собственные (л о к а л ь н ы е) пере- менные. Необходимо просто при к а ж д о м обращении к ней выполнять опе- ратор RESTORE для установки указателя на начало данных подпрограммы. П р и м е р. ─────────── NEW Ok 10 DATA 5,2:'Данные основной программы 20 DATA 7,.5:'Данные подпрограммы 30 READ A,B:?A+B;:GOSUB 40:?A+B:END 40 RESTORE 20:READ A,B:?A+B;:RESTORE 10:READA,B:RETURN'A и B - л о к а л ь н ы е переменные подпрограммы! run ·7··7.5··7 Ok Наиболее распространенной ошибкой при использовании подпрограмм являет- ся их неполное отделение от основной программы. Основными способами защи- ты от указанной ошибки являются: 1) использование оператора END; например, если п а к е т подпрограмм (совокупность нескольких подпрограмм) начинается с программной строки 100, то строка основной программы 99 END предотвратит вход в подпрограмму, начинающуюся со строки 100; 2) использование в основной программе перед первой строкой подпрограм- мы оператора GOTO k ,где k - номер программной строки, расположенной за строкой, в которой расположен оператор RETURN данной подпрограммы (см.при- мер из раздела IV.4.1). Поэтому сформулируем важный практический вывод. ┌────────────────────────────────────────────────────────────┐ │ Помещайте подпрограммы или в с а м о м к о н ц е или │ │ в с а м о м н а ч а л е основной программы ! │ └────────────────────────────────────────────────────────────┘ При случайном(!) попадании в подпрограмму без использования оператора GOSUB она выполнится нормально,но компьютер выдаст сообщение об ошибке "RETURN without GOSUB" ("RETURN б е з GOSUB"). Однако, если Вы случайно забыли поставить оператор RETURN, то интер- претатор может иногда не заметить ошибку! Он будет тщетно искать "забытый" оператор RETURN до конца программы, и, не найдя, прекратит все вычисления (т.к.программа уже будет выполнена полностью). Сообщения об ошибке не бу- дет! Берегитесь! Учтите, что операторы, стоящие за оператором RETURN в той же програм- мной строке, н и к о г д а не выполняются, поэтому за оператором RETURN целесообразно помещать только комментарии. Например, 50 RETURN '──▶ или 50 RETURN ──▶ . Поговорим теперь о совместном использовании операторов FOR...NEXT и GOSUB n. Внутри цикла использовать оператор GOSUB, м о ж н о, но оператор NEXT должен быть выполнен только п о с л е выполнения оператора RETURN. В противном случае последует сообщение: "NEXT without FOR" ("NEXT б е з FOR"). П р и м е р. ─────────── NEW Ok 5 INPUT K,N:FOR I=1 TO N:GOSUB 100:PRINT I;:NEXTI:END 100 IF K>I THEN NEXTI:RETURN ELSE RETURN run run ? 2,6 ? 0,6 NEXT without FOR in 100 ·1··2··3··4··5··6 Ok Ok С другой стороны, если цикл FOR...NEXT используется в подпрограмме, то оператор RETURN, находящийся в цикле FOR...NEXT, позволяет выйти из цикла и вернуться в основную программу. Это наводит на мысль,что наиболее эффек- тивно размещать процедуру поиска элемента массива, обладающего требуе- мыми свойствами, в н у т р и подпрограммы. Как только искомый элемент бу- дет найден, выполнится выход из подпрограммы. Однако учтите, что в момент выполнения оператора RETURN [k] любой неза- конченный цикл FOR ... NEXT в подпрограмме заканчивается и часть стеково- го пространства, которое он (цикл) занимал, освобождается! П р и м е р. Вывести на экран дисплея первое нечетное число,встретивше- ─────────── еся в целочисленном массиве A(K). NEW Ok 10 DEFINT A:INPUT K:DIM A(K):DATA 2,1,4,7,8 30 FOR I=1 TO K:READ A(I):NEXTI:GOSUB 100:END 100 FOR J=1 TO K:IF VAL(RIGHT$(STR$(A(J)),1))MOD2=1THEN?A(J):RETURN EL SE NEXTJ 120 PRINT "нечетных элементов в массиве нет":RETURN run run ? 3 ? 5 1 1 Ok Ok При многократном выполнении выхода из подпрограмм с помощью операторов GOTO, ON GOTO или IF...THEN...ELSE (вместо оператора RETURN) в конце кон- цов на экране может появиться сообщение об ошибке: "Out of memory" ("Н е х в а т а е т п а м я т и") . Причина возникающей ошибки довольно своеобразна:дело в том, что интер- претатор отводит сравнительно небольшой участок динамической памяти для хранения списка адресов возврата из подпрограмм.Такой список организуется в виде стека и называется р а б о ч и м с т е к о м. Каждый раз при вы- зове подпрограммы в стек заносится соответствующий этому вызову а д р е с в о з в р а т а, занимающий 7 байтов. При выполнении оператора RETURN из стека извлекается адрес возврата, записанный последним, и происходит пере- дача управления по этому адресу, после чего он удаляется из стека. Опера- торы, подобные GOTO или IF...THEN...ELSE,осуществляют выход из подпрограм- мы, не затрагивая стека! Если такой выход из подпрограмм происходит часто, то адреса из стека не удаляются, а лишь добавляются при каждом новом вызо- ве подпрограммы, так что в результате размер стека может превысить величи- ну отведенного ему участка памяти. В итоге программа прекращает работу, и выдается сообщение об ошибке. П р и м е р. 10 GOSUB 20:END ─────────── 20 FOR I=1 TO 1:K=K+1:GOTO 10:NEXTI:RETURN run а теперь... print K Out of memory in 100 ·894 Ok Ok В программе может быть несколько операторов RETURN, относящихся к одно- му оператору GOSUB n . Отметим,что наличие оператора RETURN в некотором месте подпрограммы еще не означает фактического окончания подпрограммы в данном месте. П р и м е р. Написать программу,вычисляющую значение функции y=│ x+x²│ ─────────── в точке x=A(не применяя функции ABS()). NEW Ok 10 INPUT A:U=A+A^2:GOSUB 100:PRINT Z:END 100 'Подпрограмма вычисления │x│: аргумент U,результат Z 110 IF U>=0 THEN Z=U:RETURN ELSE Z=-U:RETURN run ? -4 12 Ok Подпрограмма может, в свою очередь, вызывать другую подпрограмму, та - другую и так далее. Глубина вложения (степень вложения) подпрограмм огра- ничивается лишь размерами стека. Наглядно это можно представить себе следующим образом. Пусть Вас из Куйбышева послали в Москву на повышение квалификации, а оттуда еще в Ленинград на курсы. По окончании этих курсов Вы возвращаетесь в Москву,за- канчиваете учебу там и только после этого возвращаетесь домой. Вложенные подпрограммы являются довольно мощным средством разработки и отладки больших программ. Используя принцип вложений, можно не только раз- бивать сложную программу на отдельные модули и для каждого из них писать свою подпрограмму, но и р а з д е л я т ь на м о д у л и любые подпро- граммы. Чем меньше будет каждый выделенный программный модуль,тем легче будет его программировать и отлаживать и тем больше вероятность его много- кратного использования в других программах! "Трудности, обусловленные бессистемным написанием (без использования мо- дульной структуры) большой и сложной программы,можно сравнить с трудностя- ми, возникающими при попытке съесть сразу ц е л и к о м весь батон кол- басы; в то же время, если разрезать колбасу на ломтики, то съесть ее не представит никакого труда" (Л.Пул). Приведем пример, иллюстрирующий вложение подпрограмм: NEW Ok 1' Программа вычисления суммы вида 2' k k k 3' S = x + x +...+ x , 4' 1 2 n 5' где x - корни линейного алгебраического уравнения n-ой степени 6' i 7'Алгоритм решения поставленной задачи основан на формулах Ньютона,при- веденных в книге: А.П.Мишина, И.В.Проскуряков "Высшая алгебра". М.:ГИФ- МЛ, 1962, гл.III, 3, с.245. 11 INPUT "Укажите степень многочлена";N:INPUT"Укажите k";K 15 DIM A(N) 'Описан массив коэффициентов уравнения! 18 PRINT"Вводите коэффициенты уравнения" 20 FOR I=0 TO N:INPUT A(I):NEXT 'Итак, массив А(N) введен! 40 DIM SIG(N):FOR I=1 TO N:SIG(I)=(-1)^I*A(I)/A(0):NEXTI 80 IF N>=K THEN DIM S(N):A1=N:A2=K:GOSUB 200 ELSE DIM S(K):A1=K:A2=N:G OSUB 300 110 PRINT S(K):END 200 '¤¤¤¤¤ Начало подпрограммы 1 ¤¤¤¤¤ 205 S(1)=SIG(1):FOR J=2 TO A2:S(J)=(-1)^(J+1)*J*SIG(J) 230 FOR I=1 TO J-1:S(J)=S(J)+(-1)^(J-I+1)*S(I)*SIG(J-I) 250 NEXTI:NEXTJ:RETURN '──▶ 300 '¤¤¤¤¤ Начало подпрограммы 2 ¤¤¤¤¤ 305 GOSUB 200 'Вот оно, в л о ж е н и е подпрограмм! 360 FOR J=N+1 TO K:S(J)=0 380 FOR I=1 TO N:S(J)=S(J)-(-1)^S(J-I)*SIG(I) 400 NEXT I,J:RETURN '──▶ run Укажите степень многочлена? 2 Укажите k? 2 Введите коэффициенты уравнения ? 1 ? 0 ? -1 2 Ok IV.4.1. П р и м е р ы П р и м е р 1. Написать программу, вычисления числа сочетаний из m ───────────── по n по формуле: n m! С = ──────── , (m≥n). m n!(m-n)! Целесообразно разработать подпрограмму вычисления факториала и затем трижды (почему?) обратиться к ней из основной программы. Итак, NEW Ok 40 INPUT "Введите значения m,n";M,N:GOTO 100 ───┐ 50 'Подпрограмма вычисления факториала F! │ 60 F=1:FOR J=1 TO K:F=F*J:NEXTJ │ 90 RETURN 'Конец подпрограммы! │ 100 K=M:GOSUB 60:M1=F ◀──────────────────────┘ 110 K=N:GOSUB 60:N1=F 120 K=M-N:GOSUB 60:R1=F 130 CMN=M1/N1/R1 140 ? "Число сочетаний из М=";M;"по N=";N;"равно";CMN:END run Введите значения m,n? 6,3 Число сочетаний из M= 6 по N= 3 равно 20 Ok Заметим, что оператор GOSUB может оказаться полезным в качестве коман- ды прямого режима. Если Ваша программа состоит из подпрограмм, которые Вы хотите проверить, то, используя команду GOSUB в прямом режиме,можно войти в любую подпрограмму. После выполнения оператора RETURN система MSX-BASIC снова вернется в режим прямого выполнения команд. В примере 1, например, можно проверить работоспособность подпрограммы следующим образом (находясь в прямом режиме!): F=1:k=4:GOSUB 60 Ok print F 24 Ok Ибо это недостойно совершенства человеческого, подобно рабам тратить часы на вычисления. Г.В.Лейбниц П р и м е р 2. Составить программу, которая позволяет методом половин- ───────────── ного деления (дихотомии) на отрезке [A,B] с точностью E определить какой-либо (!) вещественный корень уравнения F(x)=0, где F(x) непрерывна на [A,B] и на концах отрезка принимает значения разных знаков (F(A)·F(B)<0). Пусть, например, x x F(x)=cos e - sin π , A=1, B=3, E=0.00001. NEW Ok 10 INPUT A,B,E 20 X=A:GOSUB 200:F1=Y 30 X=(A+B)/2 40 GOSUB 200:F2=Y:IF Y=0 THEN 90 50 IFSGN(F1)*SGN(F2)>0 THEN 70 60 B=X:GOTO 80 70 A=X:F1=F2 80 IF B-A>E THEN 30 90 PRINTUSING "Корень####.##### точность##^^^^";X,E 100 END 200 Y=COS(EXP(X))-SIN(EXP(X*LOG(3.14159))) 210 RETURN run ? 1,3,.00001 Корень···1.27163·точность·1Е-05 Оk П р и м е р 3. Если у Вас есть знакомый художник, попросите его разде- ───────────── лить произвольный отрезок на две неравные части. Возмож- но он сделает это в золотом отношении, если его чувство меры воспитано на классических образцах. Такое чувство меры целесообразно "внушить" компьютеру, которому часто приходится отыскивать единственную точку минимума некоторой функции y=f(x) на отрезке [a,b]. Основа алгоритма - последовательное приближение к мини- муму до достижения заданной точности E. NEW Ok 10 'Поиск минимума функции y=f(x) на отрезке [a,b] методом золотого се- чения 20 DEFFN Y(X)=-X^2+5: 'Вид функции 30 INPUT"A,B,точность";A,B,E 40 GOSUB 110:GOSUB120 50 IF ABS(B-A)Y2 THEN 70 65 B=X2:X2=X1:Y2=Y1:GOSUB 110:GOTO 80 70 A=X1:X1=X2:Y1=Y2:GOSUB120 '──▶ 80 GOTO 50 90 X=(A+B)/2:PRINT"Y мин=";FNY(X);"при x=";X 100 END 110 X1=.618*A+.382*B:Y1=FNY(X1):RETURN '──▶ 120 X2=.382*A+.618*B:Y2=FNY(X2):RETURN '──▶ run A,B,точность? -1,4 ?? 0.00001 Y мин=-10.999971821564 при x= 3.999996477694 Ok П р и м е р 4. Вычислить π ───────────── 1 ⎧ ┌ sin(10·x)┐6 -·│ │──────────│ dx π ⎭ └ sin(x) ┘ 0 по формуле парабол (формуле Симпсона). Внимание! Интеграл несобственный! NEW Ok 20 INPUT "Нижний предел";А 30 INPUT "Верхний предел";B 40 INPUT "Количество точек";M 70 S=0:H=(B-A)/M 80 S1=0:FOR X=A+H/2 TO B-H/2 STEP H 90 GOSUB 180:S1=S1+Y:NEXT:S1=S1*4 100 S2=0:FOR X=A+H TO B-H STEP H 110 GOSUB 180:S2=S2+Y:NEXT:S2=S2*2 120 X=A:GOSUB 180:S=S+Y 130 X=B:GOSUB 180:S=S+Y 140 S=(S+S1+S2)*H/6 160 PRINT"Интеграл = ";S:END 180 Y=(SIN(10*X)/SIN(X))^6/(4*ATN(1)):RETURN ──▶ run run Нижний предел? 0.00000001 Нижний предел? 0.00000001 Верхний предел? 3.14159265 Верхний предел? 3.14159265 Количество точек? 250 Количество точек? 500 Интеграл = 55251.99567425 Интеграл = 55251.995674258 Ok Ok П р и м е р 5. Написать программу, осуществляющую лексикографическое ───────────── упорядочение (расположение в алфавитном порядке) масси- ва фамилий на русском языке (после фамилий можно указывать инициалы,напри- мер: Бобров А.В.). NEW Ok 10 DATA " ",".","А","Б","В","Г","Д","Е","Ж","З","И","Й","К","Л","М","Н ","О","П","Р","С","Т","У","Ф","Х","Ц","Ч","Ш","Щ","Ы","Ь","Э","Ю","Я" 15 DATA " ",".","-","а","б","в","г","д","е","ж","з","и","й","к","л","м ","н","о","п","р","с","т","у","ф","х","ц","ч","ш","щ","ы","ь","э","ю", "я" 20 INPUT"Введите количество фамилий";S:DIM C$(S) 30 FOR I=1TOS:INPUT"Введите очередную фамилию";C$(I):NEXTI 40 GOSUB 190 50 DIM N(L1,S) 56 FOR I=1 TO S:RESTORE 10:FOR J=1 TO 33:READB$ 57 IF B$=MID$(C$(I),1,1) THEN N(1,I)=J 58 NEXTJ 70 FOR K=2 TO LEN(C$(I))-4 71 IF MID$(C$(I),K-1,1)="-"THEN RESTORE 10 ELSE RESTORE 15 80 FOR J=1 TO 34 90 READ B$:IF B$=MID$(C$(I),K,1) THEN N(K,I)=J 100 NEXT J,K 101 FOR K=LEN(C$(I))-3 TO L1:RESTORE 10 103 FOR J=1 TO 33 105 READ B$:IF B$=MID$(C$(I),K,1) THEN N(K,I)=J 107 NEXT J,K 108 NEXT I 110 FOR K=1 TO L1 120 FOR I=1 TO S-1:FORJ=I+1 TO S 130 IF MID$(C$(I),1,K)=MID$(C$(J),1,K) THEN GOTO 140 ELSE IF(N(K,I)>N( K,J))AND(MID$(C$(I),1,K-1)=MID$(C$(J),1,K-1)) THEN SWAP C$(I),C$(J):FO R L=1 TO L1:SWAP N(L,I),N(L,J):NEXT L 140 NEXT J,I,K 150 CLS 'Очистим экран дисплея! 160 PRINT SPC(10);"Итоговый список" 170 FOR I=1 TO S:PRINT SPC(10);STR$(I);". ";C$(I):NEXTI 180 END 190 L1=0:FOR P=1 TO S:IF LEN(C$(P))>L1THEN L1=LEN(C$(P)) 200 NEXT:RETURN run Введите количество фамилий? 4 Итоговый список Введите очередную фамилию? Ухин И.Н. 1. Лим А. Введите очередную фамилию? Ми-Ка М.У. 2. Ми-Ка М.У. Введите очередную фамилию? Ми-Ша А.А. 3. Ми-Ша А.А. Введите очередную фамилию? Лим А. 4. Ухин И.Н. Ok П р и м е р 6. Абсолютно простым числом назовем натуральное число, об- ───────────── ладающее следующим свойством: при любой перестановке цифр данного числа образуется также простое число. Найдите все абсолютно простые числа, принадлежащие [C,E]. NEW Ok 1 CLS 'Вначале очистим экран! 2 INPUT"Введите два натуральных числа через запятую,причем второе числ о должно быть больше первого (эти числа задают диапазон,в котором ищут ся абсолютно простые числа)";C,E 3 PRINT"Вы хотите узнать всю правду об абсолютно простых числах, лежащ их на отрезке[";C;",";E;"] ? Пожалуйста..." 4 FOR A=C TO E:IF A<10AND(A=1ORA=2ORA=3ORA=5ORA=7)THEN PRINTA;:NEXTA E LSE IF A<10AND(A=4ORA=6ORA=8ORA=9)THEN NEXTA ELSE A$=MID$(STR$(A),2) 5 N=LEN(A$):DIM A(N) 10 FOR L=1TO N:A(L)=VAL(MID$(A$,L,1)):NEXT L:GOSUB 200 20 I=N 30 GOTO 110 40 GOSUB 300:J=N-1 50 IF A(J)>=A(J+1)ANDJ>0 THEN J=J-1:GOTO 50 60 I=J 70 IF I>0 THEN J=N:GOTO 80 ELSE GOTO 110 80 IF A(I)>=A(J) THEN J=J-1:GOTO 80 90 SWAP A(I),A(J):P1=I+1:P2=N 100 IF P10 THEN GOTO 40 120 ERASEA:IF JJ<>1 THEN PRINT A;:NEXT AELSE JJ=0:NEXTA 125 PRINT:PRINT"Надеюсь, Вы остались довольны?!" 130 END 190 'Подпрограмма,производящая сортировку массива A(N),состоящего из ц ифр числа А. 200 FOR M=1 TO N-1:FOR S=M+1 TO N 210 IFA(M)<=A(S)THEN NEXT:NEXTELSESWAP A(M),A(S):NEXT:NEXT 220 RETURN 290 'Подпрограмма,позволяющая определить,является ли число V,составлен ное из цифр числа A, простым. 300 V=0:FOR P=1TON:V=V+A(P)*10^(N-P):NEXT 310 FOR Q=2 TO INT(SQR(V)) 320 IF VMODQ=0 THEN JJ=1:RETURN ELSE NEXT Q:RETURN run Введите два натуральных числа через запятую, причем второе число должн о быть больше первого (эти числа задают диапазон, в котором ищутся абс олютно простые числа)? 1,100 Вы хотите узнать всю правду об абсолютно простых числах,лежащих на отр езке[ 1 , 100 ] ? Пожалуйста... ·1··2··3··5··7··11··13··17··31··37··71··73··79··97 Надеюсь, Вы остались довольны? Ok П р и м е р 7. ───────────── 10'**************************************************** 30'* Программа LONGMULT * 50'* позволяет найти точное значение произведения * 70'* не более чем 210-значных чисел * 81'* Мах. время работы - 1.5 мин. * 83'**************************************************** 90 CLEAR 1000:DIMA(30),C(31,61),D(62),D$(62),B(30),S(62):CC=10000000! 92 DEFFND$(X)=RIGHT$("0000000"+RIGHT$(STR$(X),LEN(STR$(X))-1),7):CLS 100 PRINT"Введите 1-й множитель":PRINT"a=";:GOSUB 150 110 FOR I=1TO N:A(I)=S(1):NEXT:NA=N 120 ?:PRINT"Введите 2-й множитель":PRINT"b=";:GOSUB 150 130 FOR I=1 TO N:B(I)=S(I):NEXT:NB=N:GOSUB 190 135 IF D(1)=0 THEN S=2 ELSE S=1 140 PRINT:PRINT"a*b=";:FOR I=S TO NA+NB:PRINT FND$(D(I));:NEXT 145 PRINT :PRINT:END 150 VV$="" 160 S$=INKEY$:IF S$=""THEN160 ELSE IF S$=CHR$(13) THEN PRINT:GOTO170 E LSE IF ASC (S$)<48 OR ASC(S$)>57 THEN160 ELSE PRINT S$;:VV$=VV$+S$:GOT O160 170 N=LEN(VV$):IFNMOD7=0THEN180 ELSE VV$="0"+VV$: GOTO170 180 N=N/7:FOR I=1 TO N:S(I)=VAL(MID$(VV$,1+(I-1)*7,7)):NEXT:RETURN 190 '∗∗∗ Собственно длинное умножение ∗∗∗ 200 FOR I=NB TO 1 STEP-1:S=0 210 FOR J=NA TO 0 STEP-1 220 C(I,J+I)=S+B(I)*A(J)-INT((S+B(I)*A(J))/CC)*CC:S=INT((S+B(I)*A(J))/ CC):NEXT:NEXT 230 S=0:FORJ=NA+NBTO1 STEP-1:FORI=1TONB:D(J)=D(J)+C(I,J):NEXT:D(J)=D(J )+S:S=INT((D(J)+S)/CC):D(J)=D(J)-INT(D(J)/CC)*CC:NEXT:RETURN run Введите 1-й множитель a=11111111111111111111111111111111111111111111111111111 Введите 2-й множитель b=10000000000000000000000000000000000000000000000000001 a*b= 11111111111111111111111111111111111 11111111111111111211111111111111111 11111111111111111111111111111111111 Ok У попа была собака, он ее любил. Она съела кусок мяса - он ее убил! Убил и закопал, и надпись написал: "У попа была собака, он ее любил. Она съела кусок мяса - ..." Из русского народного фольклора Допустимо использование рекурсивных подпрограмм. Р е к у р с и е й называется обращение подпрограммы (функции) к самой себе непосредственно или посредством других подпрограмм. Такие программы (функции) называются р е к у р с и в н ы м и. Само слово "рекурсия" озна- чает "возвращение" (лат. "recursio"). В программировании различают два типа рекурсии - рекурсивное определе- ние или п р я м у ю рекурсию и рекурсивное использование или к о с - в е н н у ю рекурсию. Рекурсивное использование - это способ описания процесса через подпро- цессы, идентичные основному процессу, а рекурсивное определение - способ описания процесса через самого себя. Рекурсия получается в программах, реализующих алгоритмы, которые содер- жат р е к у р р е н т н ы е формулы, то есть формулы,в которых значение функции от некоторого аргумента X выражается через значение этой же функ- ции, но от другого аргумента Y,который в каком-то смысле "предшествует" X. Рекуррентной является, например,формула вычисления факториала: F(k)= { 1 , если k=1 , { F(k-1)·k, если k>1 . П р и м е р 1. Составим программу вычисления факториала натурального ───────────── числа К, содержащую рекурсивную подпрограмму. NEW Ok 10 INPUT K:F=1:GOSUB 100 '──▶ 30 PRINT F:END 90 'Внимание! Рекурсивная подпрограмма! 100 IF K>1 THEN F=F*K:K=K-1:GOSUB 100 '──▶ 110 RETURN '──▶ run run run run ? 4 ? 6 ? 48 ? 49 24 720 1.2413915592536E+61 Overflow in 100 Ok Ok Ok Ok Конечно, любая рекурсивная подпрограмма может быть написана как цикли- ческая программа. Например,последнюю программу можно переписать следующим образом: 10 INPUT K:F=1 20 IF K>1 THEN F=F*K:K=K-1:GOTO 20 30 PRINT F:END Но многим программистам больше нравится использование рекурсивных под- программ, несмотря на то, что коварство рекурсии проявляется в том,что бы- вает довольно трудно заметить дефект программы или алгоритма,а в цикличес- ком процессе все на виду! П р и м е р 2. Пользуясь рекуррентной формулой ───────────── 0 m n-m+1 m-1 C = 1 ; C = ────── · C ,(∗) n n m n ─── вычислить число сочетаний из n по m при m,n=1,k, k≥1, m≤n. Приведем два варианта программы. a) 10 INPUT K 20 FOR N=0 TO K:C=1:FOR M=1 TO N:IF M>N THEN NEXTN ELSE C=(N-M+1)/M *C:PRINT N;M;FIX(C+.5):NEXT:NEXT run ? 3 ·1··1··1 ·2··2··1 ·3··2··3 ·2··1··2 ·3··1··3 ·3··3··1 b) NEW Ok Ok 5 'Программа находит число сочетаний из N по M по формуле (∗) с при менением рекурсивной подпрограммы. 10 INPUT N,M:C=N:GOSUB100:PRINT FIX(C+.5):END 100 IF M>1THEN C=C*(N-M+1)/M:M=M-1:GOSUB100:RETURN ELSE RETURN run run run далее... Ok ? 232,231 ? 233,232 ? 4080,4079 print m 232 0 ◀── ?! Out of memory in 100 2 Ok Ok Ok Ok П р и м е р 3 [6]. ───────────── NEW Ok 100 INPUT "Строка для сжатия:";FS$ 109 'Удаление пробелов из FS$. 110 S$=FS$:RMV$=" ":GOSUB 200 130 PRINT S$:END 140 '∗∗∗∗ Рекурсивная подпрограмма сжатия строк. ∗∗∗∗ 150 'В RMV$ - удаляемые символы 160 'В S$ - исходная строка и результат 200 IF INSTR(1,S$,RMV$)<>0 THEN S$=LEFT$(S$,INSTR(1,S$,RMV$)-1)+RIGHT $(S$,LEN(S$)-INSTR(1,S$,RMV$)):GOSUB 200 210 RETURN Сравните: NEW Ok 10 INPUT"Строка для сжатия:";A$ 20 FOR I=1 TO LEN(A$):C$=MID$(A$,I,1) 30 IF C$<>" " THEN B$=B$+C$ 40 NEXT:PRINT B$ Существует ограничение на число обращений подпрограммы к себе самой. Оно зависит от нескольких факторов,в частности от количества других вло- женных одна в другую подпрограмм, выполняемых в этот же момент времени, и от размеров рабочего стека. Отметим, что понятие рекурсии охватывает также и весьма интересную си- туацию, при которой первая подпрограмма вызывает вторую, а та в свою оче- редь вызывает первую! IV.5. ОПЕРАТОР ON GOSUB Кроме оператора перехода на подпрограмму в MSX-BASIC есть оператор вы- бора подпрограмм (оператор-"переключатель"). Его общий вид: ON β GOSUB n1,n2,...nk где: ON("на"),GOSUB("to GO to SUBroutine"-"идти к подпрограмме") - служеб- ные слова; β - арифметическое выражение; n1,n2,...,nk - номера начальных строк подпрограмм. Выполнение оператора ON...GOSUB начинается с вычисления целой части значения арифметического выражения β, которую мы обозначим p. Далее, если p ∈ {1,2,...,k}, где k - целое положительное число, то уп- равление переходит к строке np . Если p=0 или p>k, то выполняется оператор, следующий за ON.После выпол- нения соответствующей подпрограммы управление передается оператору, распо- ложенному за ON GOSUB . Если p<0, то компьютер выдает сообщение об ошибке: "Illegal function call". П р и м е р 1. ───────────── NEW Ok 20 INPUT "Ваш выбор (1-3)";CH 27 ON CH GOSUB 31,32,33:END 31 PRINT "1":RETURN'Попадаем сюда, если CH=1 32 PRINT "2"'RETURN'Попадаем сюда, если CH=2 33 PRINT "3"'RETURN'Попадаем сюда, если CH=3 run Ваш выбор (1-3)? 2 2 Ok П р и м е р 2. ───────────── NEW Ok 10 PRINT "Draw,Print,Change,Quit:";:I$=INPUT$(1) 20 ON INSTR(2," DdPpCcQq",I$)/2 GOSUB 100,200,300,400 30 PRINT:GOTO 10 100 PRINT "D":RETURN '──▶ 200 PRINT "P":RETURN '──▶ 300 PRINT "C":RETURN '──▶ 400 PRINT "Q":RETURN '──▶ run Draw,Print,Change,Quit:█ Draw,Print,Change,Quit: ◀── нажата клавиша "а" Draw,Print,Change,Quit:Q ◀── нажата клавиша "q" Draw,Print,Change,Quit:P ◀── нажата клавиша "p" ··· Обратите внимание на примеры из раздела III.3.! В ы в о д ы [8]. При применении подпрограмм BASIC придерживайтесь сле- ─────────────── дующих правил: 1. Четко обозначайте начало и конец каждой подпрограммы. Если это воз- можно, выделяте их путем отступа операторов вправо. 2. Никогда не пользуйтесь оператором GOTO для входа в подпрограмму и для выхода из нее. Каждую подпрограмму надо рассматривать как независимый логически завершенный м о д у л ь . 3. Имейте под рукой список глобальных входных переменных и выходных ре- зультатов каждой подпрограммы. Лучше всего оформить его комментариями к программе с помощью операторов REM . 4. Обязательно убедитесь, что в подпрограмме не изменяются значения та- ких внешних переменных, как счетчики циклов. Если это возможно, в каждой подпрограмме вводите свой принцип именования внутренних переменных. 5. В отличии от функций, подпрограммы не появляются в программе до то- го, как ими будут пользоваться, поэтому полезно группировать подпрограммы вместе после оператора END, указанного в конце основной программы. Д о п о л н е н и е 1 [77]. Программа позволяет умножить два числа, ────────────────────────── причем каждое из них может иметь "л ю - б о е" количество цифр при следующих ограничениях: в произведении должно содержаться не более 765 цифр и длина каждого из чисел должна быть ограни- чена возможной длиной строки. В заключение отметим, что приведенная программа работает неправильно либо когда одно из введенных чисел меньше 10, либо когда их произведение меньше 1000. Безусловно имеет смысл сделать программу "защищенной" в этом отношении! 5 CLEAR 1000 10 DIM A(255),B(255),C(255) 20 T=1000:Z$="000" 30 PRINT"Точное произведение целых чисел" 40 INPUT"Введите первое число: ";A$ 50 LA=LEN(A$):NA=INT((LA-1)/3) 60 FOR I=0 TO NA-1 70 A(I)=VAL(MID$(A$,LA-2-3*I,3)) 80 NEXT I 90 A(NA)=VAL(LEFT$(A$,LA-3*NA)) 100 INPUT"Введите второе число: ";B$ 110 LB=LEN(B$):NB=INT((LB-1)/3) 120 FOR I=0 TO NB-1 130 B(I)=VAL(MID$(B$,LB-2-3*I,3)) 140 NEXT I 150 B(NB)=VAL(LEFT$(B$,LB-3*NB)) 160 NC=NA+NB+1 170 FOR I=0 TO NC:C(I)=0:NEXT I 180 FOR I=0 TO NA 190 FOR J=0 TO NB 200 K=I+J:X=A(I)*B(J)+C(K) 210 Y=INT(X/T):C(K)=X-T*Y 220 IF Y>0 THEN K=K+1:X=Y+C(K):GOTO 210 230 NEXT J 240 NEXT I 250 PRINT "Произведение = "; 260 IF C(NC)=0 THEN NC=NC-1 270 PRINT C(NC) 280 FOR I=NC-1 TO 0 STEP -1 290 PRINT",";RIGHT$(Z$+STR$(C(I)),3); 300 NEXT I 320 END run Точное произведение целых чисел Введите первое число: 12345678 Введите второе число: 987654321 Произведение = 12 ,193,262,222,374,638 Оk print 12345678*987654321 1.2193262222375E+16 Ok run Точное произведение целых чисел Введите первое число: 11111111111111111111 Введите второе число: 6666666666666666666666666666666666666666 Произведение = 74 , 74, 74, 74, 74, 74, 73,333,333,333,33 3,333,333,325,925,925,925,925,925,926 Ok print 11111111111111111111*6666666666666666666666666666666666666666 7.4074074074074E+58 Ok Д о п о л н е н и е 2[90]. Нахождение факториалов "огромных" чисел. ────────────────────────── 10 DIM A(100):PRINT"Введите число N":INPUT N:A(1)=1:J=1 60 FOR I=2 TO N 80 P=0 90 FOR K=1 TO J 100 C=A(K)*I+P:P=INT(C/10):A(K)=C-P*10 130 NEXT K 140 IF P=0 GOTO 200 150 J=J+1 160 IF J>100 THEN PRINT"Не хватает места в массиве":STOP 170 A(J)=P-INT(P/10)*10:P=INT(P/10) 190 GOTO 140 200 NEXT I 210 PRINT STR$(N);"!="; 220 FOR K=J TO 1 STEP -1:PRINT RIGHT$(STR$(A(K)),1);:NEXT K run Введите число N ? 23 23!=25852016738884976640000 Ok run Введите число N ? 50 50!=30414093201713378043612608166064768844377641568960512000000000000 Ok