ГЛАВА 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$.