I.7.5. Ф у н к ц и я RND . П с е в д о п е р е м е н н а я TIME Подробнее остановимся на функции RND. При п е р в о м прочтении раз- дел, касающийся описания этой функции можно (и, пожалуй, нужно!) п р о - п у с т и т ь ! Вначале отметим, что с л у ч а й н ы е и п с е в д о с л у ч а й - н ы е числа - числа, последовательность появления которых обладает теми или иными статистическими закономерностями. Различают с л у ч а й н ы е числа, генерируемые (образуемые) каким-либо стохастическим устройством, и п с е в д о с л у ч а й н ы е числа,конструируемые с помощью арифметичес- ких алгоритмов. Надо сказать, что используемые в современных компьютерах арифметичес- кие алгоритмы обладают недостатком,несовместимым с понятием случайности: последовательность выдаваемых ими чисел периодична. И хотя повторяющийся фрагмент этой последовательности может быть весьма длинным ( миллионы, миллиарды чисел ), случайной ее уже не назовешь. Поэтому и принято на- звание: д а т ч и к ( или г е н е р а т о р ) псевдослучайных чисел. Случайные и псевдослучайные числа используются на практике в теории игр, математической статистике, методе статистических испытаний для конк- ретной реализации недетерминированных алгоритмов и поведения, предсказуе- мого лишь "в среднем". Например, если очередное случайное число равно 0,то игрок выбирает пер- вую стратегию, а если 1, то - вторую. Общий вид обращения к функции RND: RND(α) , где: RND ("RaNDom"-"случайный") - имя встроенной функции; α - арифметическое выражение. Значением функции является п с е в д о с л у ч а й н о е число β. β не является полностью случайным, однако, период повторения так велик,что его можно рассматривать как случайное. В дальнейшем под и н и ц и а л и з а ц и е й переменной (аргумента) будем понимать присвоение переменной значения. Для аргумента α возможны три варианта: 1) α < 0; говорят,что при α<0 происходит"выбор случайной последователь- ности из уже имеющейся совокупности случайных последовательностей". Генератор псевдослучайных чисел выдает новое псевдослучайное число при каждом н о в о м отрицательном значении α. Последующие обращения к гене- ратору псевдослучайных чисел с помощью функции RND будут возвращать в Ва- шу программу такое же псевдослучайное число. П р и м е р 1. 10 INPUT N ───────────── 20 FOR I=1 TO 3:PRINT CSNG(RND(-ABS(N))):NEXT I run run run ? 1 ? 2 ? 3 .0438982 .943898 .843898 .0438982 .943898 .843898 .0438982 .943898 .843898 Ok Ok Ok Обратите внимание, что при выборе случайной последовательности исполь- зуется н е с л у ч а й н ы й аргумент! Чуть ниже будет указано, как вы- брать последовательность "псевдослучайно". Таким образом, если Вы хотите при каждом прогоне Вашей программы полу- чать одно и то же псевдослучайное число, поместите в начале этой програм- мы строку вида: Z = RND(отрицательное число) 2) α > 0 ; возвращается следующее псевдослучайное число из последовате- льности, заданной последней инициализацией генератора; последовательность псевдослучайных чисел одна и та же для любого положительного значения α. Говорят, что при α>0 происходит "выбор случайного числа из выбранной ра- нее случайной последовательности"; 3) α=0 ; повторяется вывод предыдущего случайного числа. Это удобно, поскольку таким образом можно сохранить последнее используемое в програм- ме псевдослучайное число. П р и м е р 2. 10 INPUT N ───────────── 20 FOR I=1 TO 3:?CSNG(RND(ABS(N))):NEXTI:?CSNG(RND(0)) run run ? 1 ? 2 .595219 .595219 .106586 .106586 .765977 .765977 .765977 .765977 Ok Ok Все генерируемые псевдослучайные числа содержат 14 значащих цифр и на- ходятся в интервале (0,1). Для генерации целого псевдослучайного числа, лежащего на отрезке [X,Y], применяется оператор присваивания вида: Z = INT((Y-X+1)*RND(1)+X) П р и м е р 3. 10 INPUT X,Y ───────────── 20 PRINT INT((Y-X+1)*RND(1)+X);:GOTO 20 run ? 1,5 3 1 4 3 4 1 2 5 4 3 5 3 Break in 20 (нажато "CTRL"+"STOP") Ok При повторном запуске программы будем иметь: run ? 1,5 3 1 4 3 4 1 2 5 4 3 5 3 Break in 20 (нажато "CTRL"+"STOP") Ok Ясно,что для получения целого псевдослучайного числа, лежащего на отре- зке [0,9], можно применить оператор присваивания: Z = INT(10*RND(1)) Обычно желательно получать "абсолютно непредсказуемые" псевдослучайные числа. Чтобы добиться этого, прежде всего необходимо инициализировать ге- нератор псевдослучайных чисел в программе также псевдослучайным числом. Для этого в начале программы используется оператор вида: X = RND(-TIME) Помните, что такая инициализация должна осуществляться только один раз! Всюду далее, в тех местах программы, где необходимо получить случайное число, пишется выражение RND(1) . П р и м е р 4. 10 INPUT X,Y:G=RND(-TIME) ───────────── 20 PRINT INT((Y-X+1)*RND(1)+X);:GOTO 20 run ? 1,5 1 2 4 3 4 4 2 2 2 2 1 2 4 Break in 20 (нажато "CTRL"+"STOP") Ok run ? 1,5 4 1 1 3 2 3 1 2 3 4 1 Break in 20 (нажато "CTRL"+"STOP") Ok Отметим, что конструкция языка программирования, которая может быть использована в контексте, предполагающем присваивание значения, называет- ся п с е в д о п е р е м е н н о й . В MSX-BASICе имеется шесть псевдопеременных: TIME, SPRITE$(), MID$(α$,m,n), VDP(), MAXFILES, BASE() . Поговорим о псевдопеременной TIME. MSX - компьютер обладает счетчиком,который называется т а й м е р о м и запускается автоматически при включении машины. Таймер принимает целые значения из диапазона [0,65535]. Дойдя до 65535, он снова начинает вести отсчет от нуля; таймер обновляется каждые 18.2 минуты. Более длительные интервалы времени можно задавать программным путем или с помощью специаль- ной аппаратуры. Очевидно,что 60 "тиков" таймера соответствуют одной секун- де времени.Показания таймера и значение псевдопеременной TIME в с е г д а с о в п а д а ю т! Поэтому Вы всегда можете узнать показания таймера при помощи оператора присваивания вида: X = TIME , где TIME ("time"-"время") - служебное слово. Более того,Вы имеете возможность устанавливать новое значение таймера, используя оператор присваивания TIME = α , где α - арифметическое выражение. В результате псевдопеременная TIME получает значение, равное целой час- ти значения арифметического выражения α (0≤INT(α)≤65535). П р и м е р 5. NEW ───────────── Ok 10 INPUT T:TIME=T 20 FOR M=1 TO 1000:NEXT 30 PRINT TIME;:GOTO 20 run ? 0 134 269 403 538 672 807 941 ... Ok run ? 64999 65132 65267 65402 0 134 269 403 ... Ok П р и м е р 6. 10 TIME=0 ───────────── 20 IF TIME=65535 THEN PRINT TIME/60;"сек" ELSE GOTO 20 run далее print 1092.25/60 1092.25 сек 18.204166666667 Ok Ok Используя псевдопеременную TIME,можно учитывать время работы программы. П р и м е р 7. NEW ───────────── Ok 10 TIME=0 20 FOR K=1 TO 10000:NEXT 30 PRINT TIME/60;"сек" Используя эту программу,получим забавные таблицы для компьютеров MSX-1! Дисплей монохроматический! ┌───────┬───────┬───────┬───────┐ Время измеряется в секундах!│ К% │ К! │ К# │ К │ ┌────────────────────────┼───────┼───────┼───────┼───────┤ │ FOR K=1 TO 10000:NEXTK │ 15.3 │ 24.7 │ 27.1 │ 27.3 │ ├────────────────────────┼───────┼───────┼───────┼───────┤ │ FOR K=1 TO 10000:NEXT │ 12.3 │ 21.6 │ 23.9 │ 23.9 │ └────────────────────────┴───────┴───────┴───────┴───────┘ Дисплей цветной! ┌───────┬───────┬───────┬───────┐ Время измеряется в секундах!│ К% │ К! │ К# │ К │ ┌────────────────────────┼───────┼───────┼───────┼───────┤ │ FOR K=1 TO 10000:NEXTK │ 15.58 │ 25.20 │ 27.67 │ 27.87 │ ├────────────────────────┼───────┼───────┼───────┼───────┤ │ FOR K=1 TO 10000:NEXT │ 12.53 │ 22.03 │ 24.42 │ 24.42 │ └────────────────────────┴───────┴───────┴───────┴───────┘ ...а теперь для компьютеров MSX-2 (сетевой вариант): Дисплей монохроматический! ┌───────┬───────┬───────┬───────┐ Время измеряется в секундах!│ К% │ К! │ К# │ К │ ┌────────────────────────┼───────┼───────┼───────┼───────┤ │ FOR K=1 TO 10000:NEXTK │ 12.90 │ 22.00 │ 24.13 │ 24.18 │ ├────────────────────────┼───────┼───────┼───────┼───────┤ │ FOR K=1 TO 10000:NEXT │ 10.25 │ 19.02 │ 21.08 │ 21.15 │ └────────────────────────┴───────┴───────┴───────┴───────┘ Дисплей цветной! ┌───────┬───────┬───────┬───────┐ Время измеряется в секундах!│ К% │ К! │ К# │ К │ ┌────────────────────────┼───────┼───────┼───────┼───────┤ │ FOR K=1 TO 10000:NEXTK │ 14.28 │ 24.08 │ 26.60 │ 26.70 │ ├────────────────────────┼───────┼───────┼───────┼───────┤ │ FOR K=1 TO 10000:NEXT │ 11.37 │ 20.77 │ 23.37 │ 23.27 │ └────────────────────────┴───────┴───────┴───────┴───────┘ ... и наконец, для компьютера MSX-2, отключенного от локальной сети: Дисплей монохроматический! ┌───────┬───────┬───────┬───────┐ Время измеряется в секундах!│ К% │ К! │ К# │ К │ ┌────────────────────────┼───────┼───────┼───────┼───────┤ │ FOR K=1 TO 10000:NEXTK │ 7.98 │ 17.22 │ 19.58 │ 19.80 │ ├────────────────────────┼───────┼───────┼───────┼───────┤ │ FOR K=1 TO 10000:NEXT │ 5.05 │ 14.18 │ 16.48 │ 16.48 │ └────────────────────────┴───────┴───────┴───────┴───────┘ Дисплей цветной! ┌───────┬───────┬───────┬───────┐ Время измеряется в секундах!│ К% │ К! │ К# │ К │ ┌────────────────────────┼───────┼───────┼───────┼───────┤ │ FOR K=1 TO 10000:NEXTK │ 8.37 │ 18.07 │ 20.55 │ 20.77 │ ├────────────────────────┼───────┼───────┼───────┼───────┤ │ FOR K=1 TO 10000:NEXT │ 5.28 │ 14.87 │ 17.30 │ 17.28 │ └────────────────────────┴───────┴───────┴───────┴───────┘ Запомните, что большинство операций ввода-вывода выключают таймер,и он начинает отсчет заново после окончания ввода-вывода! П р и м е р 8. NEW NEW ───────────── Ok Ok 10 DIM M(50,50) 10 DIM M(50,50),A 20 TIME=0:A=1:PRINT TIME 20 TIME=0:A=1:PRINT TIME run run 36 1 Ok Ok Приведем пример использования функции RND и псевдопеременной TIME. П р и м е р 9. NEW ───────────── Ok 5 'Нахождение числа π методом Монте-Карло 10 X=RND(-TIME):INPUT"Количество бросаний точки -";N 20 FOR I=1 TO N:X1=RND(1):X2=RND(1) 30 IF X1^2+X2^2<1 THEN IN=IN+1 40 NEXT:PRINT "π≈";4*IN/N run Количество бросаний точки - 100 π≈ 3.4 (π≈ 3.2) Ok run Количество бросаний точки - 200 π≈ 3.12 (π≈ 3.24) Ok run Количество бросаний точки - 500 π≈ 3.208 (π≈ 3.008) Ok run Количество бросаний точки - 750 π≈ 3.2213333333333 (π≈ 3.2171428571429) Ok run Количество бросаний точки - 1000 π≈ 3.204 (π≈ 3.156) Ok Справа в круглых скобках приведены результаты счета при повторном запу- ске данной программы через некоторое время с теми же значениями N. I.8. ВЫРАЖЕНИЯ Возможность использования выражений является одним из главных преиму- ществ языков программирования высокого уровня перед машинными языками. В ы р а ж е н и е - последовательность операндов, соединенных знаками операций, а при необходимости - и к р у г л ы м и скобками так,что в ре- зультате выполнения операций получается единственное значение, которое на- зывается з н а ч е н и е м в ы р а ж е н и я . Напомним, что под о п е р а н д о м мы понимаем либо константу, либо переменную (простую или индексированную), либо встроенную функцию, либо функцию пользователя (см. раздел IV.3). Заметим, что в частном случае выражение может содержать только конс- танту, имя переменной, вызов встроенной функции или функции пользователя. Итак, например, простейшими выражениями являются: 5 ; -.5Е6 ; Х1 ; "А" ; COS(Z) ; X-2>=0 . Вычисление значения выражения заключается в том, что вместо имен пере- менных и функций подставляются их значения, и выполняются заданные опера- ции. При этом учитываются п р а в и л а с т а р ш и н с т в а о п е р а- ц и й. Напомним, что вычисление значения встроенной функции или функции пользователя имеет н а и в ы с ш и й приоритет! В отличие от обычной математической записи выражения в BASICе записыва- ются в одну строку без подстрочных и надстрочных индексов. Причем,если в математике можно опустить знак умножения при записи алгебраических выраже- ний (например,2а+3b), то в BASIC это не допускается (надо писать:2*а+3*b). Нетрудно понять, чем вызвано введение такого правила:без него невозможно определить, означает ли АВ умножение А на В или это - имя переменной. Менять порядок вычислений (чтобы застраховать себя в сомнительных слу- чаях) программист может с помощью круглых скобок. Порядок работы со скоб- ками соответствует общепринятому в математике,то есть вначале вычисляется значение выражения, стоящего в скобках. Например, значение выражения A+B*COS(Z) вычисляется так же, как и зна- чение выражения A+(B*COS(Z)) . Если в выражении н е т с к о б о к , то надо внимательно следить за п о р я д к о м с т а р ш и н с т в а о п е р а ц и й . Например, многие начинающие программисты записывают для вычисления зна- чения дроби A ─── 2*B в программе выражение: A/2*B , которое равносильно выражению A ───*B , 2 ибо приоритет операций "/" и "*" одинаков! Верно записанное выражение должно иметь вид: A/2/B или A/(2*B) . Аналогично, 2^2^K означает (2^2)^K, а не 2^(2^K)! Скобки могут вкладываться одни в другие п р а к т и ч е с к и неогра- ниченно: максимальное количество вложений скобок равно 126. Если все же выражение не удовлетворяет этому ограничению, выдается со- общение: "Out of memory" ("Н е х в а т а е т п а м я т и"). I.8.1. А р и ф м е т и ч е с к и е и с т р о к о в ы е в ы р а ж е н и я А р и ф м е т и ч е с к и м выражением будем называть выражение,значе- нием которого является число. П р и м е р ы арифметических выражений : ───────────── -154.567E-1 и -154.567*10^(-1) (укажите различие!) p1 D-B^2+4*a*C SQR(A^2+B^2-2*A*B*cos(X)) (-B+ABS(D))/(2*A) T%+c%*n%-4 С т р о к о в ы м выражением будем называть выражение, значением кото- рого является строка. П р и м е р ы строковых выражений: ───────────── "А Б Б А" , AH$ s$+" "+"2" MID$(A$,3,7) I.8.2. Л о г и ч е с к и е в ы р а ж е н и я Но да будет слово ваше: да, да; нет, нет; а что сверх этого, то от лукавого. Матф.,5,37 Наряду с арифметическими и строковыми выражениями можно рассматривать л о г и ч е с к и е в ы р а ж е н и я. Разберем вначале частный случай логического выражения - о т н о ш е н и е. О т н о ш е н и е - выражение, состоящее из двух арифметических или строковых выражений, связанных знаком операции отношения. Например, X*X>=0 5<2 "А">"а" Z$+MID$(X$,2,N%)="a" Для п р о г р а м м и с т а значением о т н о ш е н и я может быть либо Т, либо F. Так, первое из приведенных выражений имеет значение Т, второе - F. Четвертое выражение принимает то или иное значение в зависимости от значе- ний строковых переменных Z$,X$ и целочисленной переменной N%. Для компьютера значением о т н о ш е н и я будет: 1) -1, если о т н о ш е н и е истинно; 2) 0, если о т н о ш е н и е ложно. Приведем пример нестандартного применения отношений. С помощью "смешан- ного" (оно содержит арифметические операции и операции отношения) выраже- ния вида: -(X>=1)*X^2-(X<1)*(X+4) программист может вычислить значение кусочно-непрерывной функции Y, описы- ваемой формулами: X² , если Х≥1, Y = { X+4 , если Х<1. Отметим, что с помощью оператора IF (см.далее раздел III.2.) вычисление значения функции Y производится следующим образом: IF X>=1 THEN Y=X^2 ELSE Y=X+4 . Л о г и ч е с к и м в ы р а ж е н и е м будем называть последователь- ность отношений,соединенных знаками л о г и ч е с к и х операций и знака- ми операций отношения. В логических выражениях, так же как в арифметических и строковых,можно (и нужно!)использовать круглые скобки. Гораздо легче запутаться в логичес- ких выражениях, чем в арифметических, поэтому если в логическое выражение входят несколько логических операций,то о б я з а т е л ь н о используй- те с к о б к и! При отсутствии скобок необходимо учитывать приоритет опе- раций. Значением логического выражения для п р о г р а м м и с т а может быть одно из двух логических значений: Т или F. Значением логического выражения д л я Э В М является либо: 1) целое число,отличное от нуля (этот случай соответствует логическому значению Т); 2) нуль (этот случай соответствует логическому значению F). Логические выражения часто называют у с л о в и я м и. Если выражение имеет значение Т, то говорят, что соответствующее условие с п р а в е д - л и в о (выполняется). В противном случае говорят,что условие не справед- ливо (не выполняется). П р и м е р ы: ───────────── 1) Z=1 AND F<4 ─▲─ ─▲─ ─▲─ │ │ │ отношение │ отношение знак логической операции 2) NOT ( A1) = (F<=41) ──▲── ▲ ───▲─── │ │ │ отношение │ отношение знак операции отношения 4) написать логическое выражение, которое имеет значение Т при выполне- нии следующего условия: a) значение переменной X находится в одном из двух интервалов (A,B) и (C,D). Ответ: (X>A AND XC AND X=0 истинно для точек, принадлежащих правой полуплоскости, а отношение Y>=0 - для точек верхней полуплоскости.Объединяя эти отношения логической операцией AND, получим искомое логическое выражение, истинное для точек, принадлежащих заданной области: X^2+Y^2<=1 AND X>=0 AND Y>=0 ; c) из отрезков длиной A, B и C можно построить треугольник. Р е ш е н и е. Как нетрудно видеть, искомое логическое выражение имеет вид: (AC)AND(C>ABS(B-A)) ; d) ближайшее к значению переменной X целое число четно и отлично от нуля. Ответ: FIX(X+.5)MOD2=0ANDFIX(X+.5)<>0; е) при делении значения целой переменной X на значение целой перемен- ной Y в остатке получается число, делящееся нацело на значение целой пере- менной Z. Ответ: (X%MODY%)MODZ%=0; 5) записать логическое выражение (A+5=0)AND(B=0)AND(K=5*B) , не прибегая к символам логических операций. Ответ: ABS(A+5)+ABS(B)+ABS(K-5*B)=0. Таким образом, логическое выражение ((A+5=0) AND (B=0) AND (K=5*B)) EQV (ABS(A+5)+ABS(B)+ABS(K-5*B)=0) имеет значение T; 6) заметим, что, вообще говоря, при записи логических выражений (усло- вий) можно обойтись без логических операций XOR, EQV, IMP,то есть логичес- кие выражения вида: ZIMPY=(NOTZ)ORY, ZXORY=(ZAND(NOTY))OR((NOTZ)ANDY), ZEQVY=NOT(ZXORY) истинны (имеют значение Т). Еще раз настойчиво рекомендуем Вам, записывая логические выражения, не жалеть скобок и не пользоваться логическими операциями, смысл которых Вам непонятен! I.9. Д о п о л н е н и е Я уверен, вы согласитесь со мной, что если стра- ница 534 застает нас только во второй главе, то первая должна быть невыносимо длинной. Конан Дойль Одним из критериев оценки производительности компьютеров является вре- мя выполнения определенных тестовых программ-"бенчмарков" ("benchmark"- "эталонный текст","benchmarking"-"определение эффективности системы (ЭВМ или программного обеспечения) посредством выполнения эталонных программ или обработки эталонных наборов данных"). В книге [21] приведено сравнение результатов выполнения одной из таких программ на ряде компьютеров и микрокалькуляторов. П р о г р а м м а - b e n c h m a r k ───────────────────────────────────── NEW Результаты эксперимента следующие: Ok персональные компьютеры: 110 PRINT "Начало";:TIME=0 IBM PC - 37 секунд, 120 K=0:DIM M(5) Apple IIe - 46 секунд, 140 K=K+1 '◀───┐ Искра 226 - 49 секунд, 150 A=K/2*3+4-5 ' │ Tandy Color - 51 секунд, 160 GOSUB 230 '───▶ ' │ Электроника НЦ-80-20 - 56 секунд, 170 FOR L=1 TO 5 ' │ Epson HX-20 - 101 секунд, 180 M(L)=A ' │ СМ-1800 - 104 секунд, 190 NEXT L ' │ калькулятор: 200 IF K<1000 THEN 140 '───▶┘ FX-702P фирмы "Casio" - >20 минут. 210 PRINT TIME/60;"сек":PRINT "Конец" 220 END 230 RETURN '──▶ ┌─────────────────────────────┐ ┌──────────────────────────────┐ │ run │ │ run Учительский │ │ Начало │ │ Начало компьютер серии │ │ 57.2 сек Компьютер серии │ │ 47.45 сек MSX-2, │ │ Конец MSX-1 │ │ Конец отключенный от │ │ Ok │ │ Ok сети │ └─────────────────────────────┘ └──────────────────────────────┘