ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.


фотообои специи

 

Часть 4

   Хотя это и срабатывает,  но усложняет и замедляет программу,
поскольку неожиданно возникает проблема  выполнения  100  вычита-
ний, которых ранее не было.  
     Соответствующий  оператор  OPTION BASE также можно использо-
вать для определения низшего элмента массива,  хотя механизм раз-
бивки на диапазоны более действенный и предпочтительный.  

                        Строковые массивы.
                        ------------------
     Элементы строковых массивов хранят строки, а не числа. Длина 
строки может быть различной:от 0 до 32767 знаков.  Обычный  стро-
ковый  объем для строк и строковых массивов составляет 64К.  Нап-
ример:  DIM a$(50) создает последовательность из  51  независимой 
строковой переменной: 

     a$(0)= "Строка средней длины"   строка из 20 знаков
     a$(1)= " "                      пустая строка (по умолчанию)
     a$(0)= SPACE$(20000)            строка из 20000 знаков
     *
     *
     *
     a$(50)="The last one"           строка из 12 знаков

                       Многомерные массивы.
                       --------------------
     Массивы могут иметь одну или несколько размерностей,  макси- 
мально - 8.  Одномерный массив,  например,  payments - это просто 
список  значений.  Двумерный массив представляет собой таблицу 
чисел с рядами и колонками данных.  Возможны также и  многомерные 
массивы, не имеющие готовых аналогов в реальном мире: 

     DIM a(15)               (одномерный список)
     DIM b(15,20)            (двумерная таблица)
     DIM c(5,5,10,20,3)      (пятимерный Блюрфкварц)
 
     Максимальное число элементов на каждую размерность - 32768.

                     Проверка связей массива.
                     ------------------------                   
     ТУРБО  БЕЙСИК  делает  все возможнре,  чтобы избавить вас от 
неприятностей,  связанных с неверными индексами  (т.е.  индексами 
либо слишком большими,  либо слищком малыми для данного массива). 
     И компилятор немедленно сообщает о неверном индексе: 

     DIM a(50)
     a(51) = 33

     Эта программа не будет транслироваться,  т.к.  ТУРБО  БЕЙСИК 
сознательно  не  будет  генерировать команду доступа к 52-му эле-
менту 51-элементного массива.  Однако,  если в качестве  индексов 
использовать переменные, компилятор не обнаружит ошибки: 

     DIM a(50)
     n = 51
     a(n) = 33

     И  хотя  данная  программа будет компилироваться без ошибки, 
все же можно поймать внедиапазонный индекс в 3-ей строке при  вы-
полнении  программы путем ее компиляции с включенным режимом "От-
ладка связей" (По проверке индексов см.  раздел "Команды  Вариан-
тов" в Главе 3).  

                  Требования к хранению массивов.
                  -------------------------------               
     По техническим причинам, связанным с быстродействием и эффе- 
ктивным использованием объема программ,  ТУРБО БЕЙСИК ограничива- 
ет размер каждого отдельного массива до 64 Килобайт, хотя в прог- 
рамме может содержаться столько 64-килобайтовых массивов, сколько 
позволяет  ЗУ.  Максимальное число элементов в массиве зависит от 
его типа, как показано ниже: 

     ----------------------------------------------------------
     Тип                      Требования к объему памяти
     ----------------------------------------------------------
     Целочисленный            2байта на элемент (32768 на 64 К)
     Длинный целочисленный    4байта на элемент (16384 на 64 К)
     С одинарной точностью    4байта на элемент (16384 на 64 К)
     С двойной точностью      8байт  на элемент (8102  на 64 К)
     Строковый                4байта на элемент (16384 на 64 К)
     ----------------------------------------------------------

     Внимание: В  элементе  строкового  массива содержится только
информация по указателям и  длине.  Собственно  строковые  данные 
хранятся  в  строковом  пространстве  и  занимают  столько  байт, 
сколько знаков в строке.  Пространство строки  максимально  может 
содержать 64К знаков.  

                    Динамическое распределение.
                    ---------------------------
     ТУРБО БЕЙСИК обеспечивает динамическое распределение памяти. 
Динамическое    распределение    означает    создание    массивов 
изменяющейся   величины   при   выполнении,   а   не  определение 
фиксированных (статических) структур при компилировании.  
     Это   позволяет  создавать  маччивы  точно  таких  размеров, 
которые необходимы для обработки данных, задаваемых программе при 
выполнении.  После завершения их функций  память,  распределенная 
динамическим   массивам,    может   быть   возвращена   и   вновь 
использована.  
     Для  создания  динамического  массива   просто   используйте 
перменные  аргументы  в  операторе  DIM;  если  есть место в ЗУ - 
массив будет  создан.  Когда  программа  завершила  использование 
этого массива,  примените опреатор ERASE(Стереть) для того, чтобы 
избавиться от  него и использовать память для других целей.  
 
    Например:

     -выяснить, сколько записей в каталоговом файле,
     -затем установить размеры динамических массивов и  загрузить 
      их 

     OPEN "PARTS.DTA" AS #1 LEN = 56
     count = LOF(1)/56
     DIM partNo(count), desc$(count), quan(couny), cost(count)
     GOSUB LoadArrays
     GOSUB UseArrays
     ERASE partNo, desc$, quan, cost

     Чтобы  воспользоваться  преимуществами динамических массивов 
ТУРБО БЕЙСИКа,  нужно лишь сделать оценочный опрос каждого масси-
ва  вашей  программы:  статический или динамический?  Имеет ли он 
фиксированный размер в соответствии  с  конфигурацией  программы, 
или  это  зависит  от некоего параметра,  величина которого неиз-
вестна до выполнения программы?  Например, массив births из ранее 
приведенного   примера  лучше  всего  создавать  как  статическую 
структуру - его величина всегда будет составлять 100 элементов.  
     Небольшим неудобством  динамических  массивов  является  тот 
факт,  что  иногда  можно  безуспешно пытаться установить размер-
ность большого массива DIM-оператором при  выполнении  программы, 
но  для  выполнения этой функции просто не будет достаточного ко-
личества свободной памяти.  Если в программе  только  статические 
массивы  и достаточно памяти для запуска - то она не будет исчер-
пана;  массивы такой программы создаются еще до того, как начина-
ется ее выполнение.  
     В связи с этим программа, использующая динамические массивы, 
должна  знать,  что  при  выполнении может оказаться недостаточно 
свободной памяти для описания требуемых массивов.  Прежде чем ус-

тановить  размерность  динамического массиа DIM-оператором,  вос-
пользуйтесь функцией  FRE(-1),  чтобы  проверить,  достаточно  ли 
места для него.  

          Описание статических или динамических массивов.
          -----------------------------------------------       
     Метаоператоры  $DYNAMIC  и  $STATIC  управляют типом задания 
массивов в программе по умолчанию.  Обычно в программе содержится 
только  один  из  этих  метаоператоров.  По  умолчанию компилятор 
подразумевает атрибут $STATIC.  
     Массивы считаются динамическими в следующих случаях:

     -если они описаны после употребления метаоператора $DYNAMIC, 
      как, например, в: 

     10 $DYNAMIC
     20 DIM A(10)

     -если явно заданы как динамические, как в:

    10 DIM DYNAMIC A(10)

     -если в операторе DIM использована переменная, как в:

     10 X% = 10
     20 DIM A(X%)

     -если массив включен в оператор COMMON, как в:

     10 DIM A(10)
     20 COMMON A(1)

     -если есть два или более операторов DIM для олного и того же 
      идентификатора массива, как в: 

     10 DIM A(10)
     20 A(0) = 10
     30 DIM A(10)

     -если массив описывается как локальный в процедуре или  функ-
      ции, как в:

     DEF FNTest%
       LOCAL A()
       DIM A(10)
       FNTest = A(10)
     END DEF

     Класс хранения массива также  может  быть  задан  атрибутами 
STATIC и DYNAMIC в DIM-операторе.  Кроме того,  массив всегда ди-
намический,  если в  соответствующем  DIM-операторе  используется 
выражение. Например: 

     $STATIC             отсюда и далее считать все массивы стати-
                         ческими,
     DIM a(40), b(20,20) поэтому a и b оба статические массивы;
     DIM DYNAMIC c(20)   атрибут DYNAMIC  отменяет примененный по
                         умолчанию  $STATIC;
     DIM d(n)            использование переменной в DIM также ус-
                         танавливает атрибут DINAMIC;
     $DYNAMIC            отсюда и далее компилятор считает мас-
                         сивы динамическими,
     DIM e(50)           поэтому e - массив динамический

     "Избавиться" от динамических массивов можно с помощью опера-
тора  ERASE:  удаление  статических  массивов  с помощью ERASE не 

восстанавливает память,  но устанавливает их  элементы  на  0  (в 
строковых массивах в нулевую строку).  

                            Выражения.
                            ----------
     Выражение состоит из операторов и операндов,  осуществляющих 
определенные операуии при вычислении выражения.  В ТУРБО  БЕЙСИКе 
существует два основных типа выражений: строковые и числовые.  
     Строковое выражение состоит из строковых констант, строковых 
переменных и строковых функций (тех,  которые оканчиваются на $), 
соединенные,  где это необходимо,  конкатенационным оператором  -
знаком плюс (+).  Строковые выражения упрощают до строки; т.е. до 
последовательности символов ASCII известной длины.  Среди  приме-
ров строковых выражений следующие: 

     "Cats and dogs"
     a$
     a$ + z$
     LEFT$(a$ + z$)
     a$ = MID$("Cats and dogs",5,3)
     RIGHT$(MID$(a$ = z$,1,6),3)

     Числовые выражения состоят из числовых констант,  переменных 
и функций,  разделяемых,  где необходимо,  числовыми операторами.  
Числовые  выражения всегда упрощаются в соответствии со значением 
одного из четырех числовых типов (целочисленному,  длинному цело-
численному, со динарной точностью, с двойной точностью).  Примеры 
числовых выражений включают: 

     37
     37/15
     a
     37/a
     SQR(37/a)
     SQR((c + d)/a) * SIN(37/a)

     При формировании числовых выражений следует  иметь  в  виду,
что определенные операции будут произведены первыми.  Ниже приве-
ден порядок вычисления выражения.  Возведение в степнь имеет выс-
ший приоритет; IMP(импликация) - низший.  

     - Возведение в степень (^)
     - Отрицание (-)
     - Умножение, Деление с плавающей запятой (*,/)
     - Целочисленное деление (\)
     - По модулю (MOD)
     - Сложение, Вычитание (+,-)
     - Операции сравнения (<,<=,=,>,>=,<>)
     - Отрицание (NOT)
     - И (AND)
     - ИЛИ, Исключающее ИЛИ(OR, XOR)
     - Эквивалентность (EQV)
     - Импликация (IMP)

     Например значение выражения 3 + 6/3 равно 5,  а не  3.  Пос-
кольку  приоритет деления выше,  чем вычитания,  операция деления 
(6/3) производится первой.  
    При проведении операций с одинаковым приоритетом  ТУРБО  БЕЙ-
СИК производит их слева направо.  Например, в выражении 4 - 3 + 6 
вычитание (4-3) производится перед сложением (3 +  6),  что  дает 
промежуточное выражение 1 + 6.  
    Операции  в  скобках имеют высший приоритет и всегда произво-
дятся первыми; внутри скобок действуют общие правила.  

                            Операторы.
                            ----------                          
     Численные  операторы  делятся  на   три   основные   группы: 
арифметические, логические и операторы сравнения.  

     Арифметические операторы.
     -------------------------
     Арифметические  операторы  производят обычные математические 
операции.  В Таблице  4-2  перечислены  арифметические  операторы 
ТУРБО БЕЙСИК в порядке возрастания приоритетов.  

              Таблица 4-2. Арифметические операторы
    ----------------------------------------------------------
    Оператор     Действие                      Пример
    ----------------------------------------------------------
    ^            Возведение в степень          10^4
    -            Отрицание                     -16
    *, /         Умножение,Деление с плваю-    45 * 19, 45 - 19
                 щей запятой
    \            Целочисленное деление         45 \ 19
    MOD          По модулю                     45 MOD 19
    +,-          Сложение, Вычитание           45 + 19, 45 - 19
    -----------------------------------------------------------

     Некоторые из этих операторов заслуживают краткого пояснения.
Обратная черта дроби (\) представляет целочисленное деление.  Це-
лочисленное деление округляет свои операнды до целых чисел и  да-
ет округленное частное без остатка;  например, 5 \ 2 равняется 2, 
а 9 \ 10 равно 0.  
    Остаток целочисленного деления  можно  определить  с  помощью 
оператора MOD& (заметьте,  что оператор MOD действителен только с 
короткими целыми числами.) Оператор MOD похож на  оператор  цело-
численного  деления,  только он показывает остаток деления,  а не 
частное; например, 5 MOD 2 равно 1 , а 9 MOD 10 равно 9.  

     Операторы сравнения.
     --------------------
     Операторы сравнения позволяют сравнивать значения двух строк 
или двух чисел (но не строки  с  числами)  для  получения  булева 
резуль-тата:   ВЕРНО  (TRUE)  или  НЕВЕРНО  (FALSE).   Результату 
сравнения  присваивается  целочисленное   значение   "-1",   если 
отношение верно, и "0" - если неверно. Например: 

     PRINT 5 > 6, 5 < 6< (5 < 6)*15

выдает  0,-1  и  -15.  Хотя полученные численные результаты можно 
использовать    в    любом    числовом    выражении    (например,  
a  =  (b*c)/13), числовые результаты, получаемые в операциях сра-
внения, как правило,  используются в IF(ЕСЛИ) или других операто-
рах  принятия  решения  для  определения  направления дальнейшего 
выполнения  программы.   
     В  Таблице  4-3 приведены операторы сравнения.  

           Таблица 4-3.   Операторы сравнения
        ---------------------------------------------------
        Оператор       Сравнение             Пример
        ---------------------------------------------------
        =              Равенство              x = y
        <>             Неравенство            x <> y
        <              Меньше, чем            x < y
        >              Больше, чем            x > y
        <=             Меньше или равно       x <= y
        >=             Больше или равно       x >= y
        ----------------------------------------------------

     Если  арифметические операторы и операторы сравнения сведены 
в одном выражении,  арифметические операторы  всегда  выполняются 
первыми.  Например,  4  + 5 < 4*3 дает всегда результат "-1"(ВЕР-
НО),  поскольку арифметические операции выполняются  до  операции 
сравнения,  которая  в  конце  проверяет правильность утверждения 
9 < 12.  

     Логические операторы.
     ---------------------                     
     Логические операторы выполняют логические (булевы)  операции 
с  целыми числами.  При использовании с операторами сравнения они 
позволяют проводить такие комплексные тесты, как 

     IF day>29 AND month=2 THEN PRINT "Error in date"
     ЕСЛИ день>29 И месяц=2 ТО ПЕЧАТАТЬ "Ошибка в дате"

     Оператор AND (И) производит логичекое умножение  целочислен-
ных  результатов,  полученных  в  двух операциях сравнения.  (AND 
имеет более низкий приоритет,  чем операторы сравнения ">" и "=", 
поэтому скобки не нужны).  Например,  если день = 29 и месяц = 2, 
обе операции сравнения дают  результат  ИСТИНA  (-1).  Лежащее  в 
основе бинарное представление целых чисел таково,  что "-1" имеет 
величину &HFFFF (все биты  включены);  "0"  -  &HOOOO,  все  биты 
выключены.  
     Затем оператор  И производит операцию логического  умножения
этих двух ИСТИННЫХ результатов:

     1111 1111 1111 1111 (-1)
AND  1111 1111 1111 1111 (-1)
     ------------------------
     1111 1111 1111 1111 (-1)

    давая ИСТИННЙ (ненулевой) результат.

     Операция  OR (ИЛИ),  называемая иногда включающее ИЛИ,  дает 
ответ ИСТИНA,  если один или оба ее  аргумента  ИСТИННЫ,  и  дает 
ответ ЛОЖЬ только если оба аргумента ЛОЖНЫ.  

     Например:

-1 OR 0 is TRUE
 0 OR 0 is FALSE
 5 > 6 OR 6 < 7 is TRUE

     Операция  XOR  (Исключающее  ИЛИ)  дает  ответ ИСТИНA,  если 
проверяемые величины разные, и ответ - ЛОЖЬ, если они равны.  

-1 XOR 0 is TRUE
-1 XOR -1 is FALSE
 5 > 6 XOR 6 < 7 is TRUE

     Функция EQV (Эквивалентно) противоположна XOR.  Она дает от-
вет ИСТИНA, если исследуемые две логические величины одинаковы, и 
ответ ЛОЖЬ, если они неодинаковы: 

-1 EQV 0 is TRUE
-1 EQV -1 is FALSE
 5 > 6 EQV 6 < 7 is TRUE

    Оператор IMP (Импликация) дает  ответ  ЛОЖЬ  только  если
первый операнд ИСТИННЕН, а второй ЛОЖЕН:

-1 OR 0 is TRUE
 0 OR 0 is FALSE
 5 > 6 OR 6 < 7 is TRUE

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

x = 500000
IF x OR y THEN GOTO Exit

     Оператор IF (ЕСЛИ) может в результате дать ошибку переполне-
ния, если x нельзя преобразовать в целое число.  

     Операции с битами.
     ------------------
     В   дополнение  к  созданию  комплексных  тестов  логические 
операторы  позволяют  управлять  базовыми  двоичными  кодами   их 
целочисленных операндов. Самые общеизвестные операции - AND, OR и 
XOR маскирование.  
     Маски  AND используются для очистки выбранных битов целочис-
ленного значения,  не затрагивая остальных битов.  Например,  для 
очистки  наиболее  значимых 2 битов целочисленной величины &H9700 
используйте AND с  маской  &H3FFF,т.е.  в  маске  содержатся  все 
единицы,  кроме тех позиций битов,  которые вы желаете привести к 
нулю: 

       1001 0111 0000 0000 &H9700
   AND 0011 1111 1111 1111 &H3FFF  (маска)
       --------------------------
       0001 0111 0000 0000 &H1700  (результат)

     Маска OR устанавливает выбранные биты целого числа, не влияя 
на остальные.  Для установок двух наиболее важных битов в  &H9700 
используйте OR с маской &HC000; т.е.  маска содержит все нули, за 
исключением позиций тех битов,  которые  вы  желаете  привести  к 
единице: 

        1001 0111 0000 0000 &H9700
     OR 1100 0000 0000 0000 &HC000  (маска)
        --------------------------
        1101 0111 0000 0000 &HD700  (результат)

     Маска XOR дополняет (обращает) выбранные целочисленные биты, 
не влияя на другие целочисленные биты.  Например, чтобы дополнить 
2  наиболее важных бита в &H9700 используйте XOR с маской &C0000; 
т.е. все нули, кроме позиций, которые нужно дополнить.  

        1001 0111 0000 0000 &H9700
    XOR 1100 0000 0000 0000 &HC000  (маска)
        --------------------------
        0101 0111 0000 0000 &H5700  (результат)

     Операции XOR часто используются в графике,  поскольку позво-
ляют перемещать объект без помех на сложном фоне. Используйте XOR 
один раз, чтобы нарисовать объект на каком-либо фоне, а затем еще 
раз на этом объекте в том же месте, чтобы стереть его,  и вернуть 
фон в первоначальне состояние.  

     Строковые операторы и операторы сравнения.
     ------------------------------------------           
     ТУРБО БЕЙСИК позволяет сравнивать строковые данные.  Строко-
вые  выражения можно проверять на эквивалентность,  а также алфа-
витное упорядоченное "больше чем" и "меньше чем".  
     Два строковых выражения равны тогда и  только  тогда,  когда 
они  содержат  абсолютно одинаковые символы в одинаковой последо-
вательности. Например: 

     a$ = "CAT"
     PRINT a$ = "CAT", a$ = "CATS", a$ = "cat"

     Строковое упорядочение основано на двух критериях и в данном 
порядке:  (1) базовые значения ASCII содержащихся знаков,  и  (2) 

длина.  Например,  A меньше B,  т.к.  ASCII код для A - 65 меньше 
кода для B - 66. Заметьте, однако, что B меньше a, т.к.  код каж-
дой  строчной  буквы больше кода соответствующей прописной (ровно 
на 32).  При "сортировке" смешанной строчно-прописной  информации 
можно использовать функции UCASE$ или LCASE$ для того,  чтобы вы-
бор регистров не влиял на сортировку.  
     Длина имеет значение только если обе строки идентичны вплоть 
до длины короткой строки;  в этом случае  более  короткая  строка 
оценивается как меньшая, чем длинная; например, "CAT" меньше, чем 
"CATS".  

                Подпрограммы, функции и процедуры.
                ----------------------------------
     Стуктура  программы  в ТУРБО БЕЙСИКе может быть упрощена ис-
пользованием подпрограмм, процедур и функций.  Подпрограмма - это 
помеченный  набор  инструкций,  исполняемых при достижении GOSUB. 
Процедура - это как бы минипрограмма,  называемая также  подпрог-
раммой,   выполняющая   некоторые  важные  части  вашей  основной 
программы. Функция - это набор команд, результатом выполнения ко- 
торых является значение числовой или смвольной (строковой)  пере- 
менной,  зависящее  от  параметров передаваемых функции.  Помещая 
комплексный и/или часто используемый код в  эти  структуры  можно 
упростить и сократить ваши программы.  
     Процедуры ТУРБО БЕЙСИКа и определяемые пользователем функции 
выходят  за  рамки простого струтурирования,  предлагаемыми подп-
рограммами.  Хотя миллионы программ в Бейсике были написаны с по-
мощью  GOSUB/RETURN  как основных оргнаизационных приспособлений, 
мы рекомендуем использовать эти улучшенные структуры.  
     Процедуры и функции ТУРБО БЕЙСИКа обеспечивают истинную  ре-
курсию,  передачу параметров и доступ к локальным,  статическим и 
глобальным переменным.  Если вы ещен не изведали преимуществ  пе-
редачи параметров,  локальных переменных и рекурсии, вам остается 
только попробовать.  
     У процедур и функций сходства больше, чем различий. Наиболее 
яркое различие состоит в том,  что функции возвращают величину  и 
таким образом,  вызываются неявно, появляясь в выражениях (с "FN" 
присоединенным впереди). Процедуры не возвращают величин и должны 
появляться явно оператором CALL (ВЫЗОВ).  
     Например,

     a = b + FNCubeROOT(c)     `вызов функции

     CALL OutChar(a)           `вызов процедуры

     Подпрограммы.
     -------------                        
     Подпрограммы - это традиционный метод разбивки программ Бей-
сик;  они состоят из помеченных групп операторов и  заканчиваются 
оператором  RETURN  (ВОЗВРАТ).  Для выполнения подпрограммы можно 
использовать оператор  GOSUB  для  указания  метки,  связанной  с 
первым  оператором подпрограммы.  При встрече с оператором RETURN 
управление переходит к оператору,  непосредственно следующему  за 
вызовом GOSUB.  
 
    Например:
                   GOSUB AddMonths
               PRINT total
             END
                   AddMonhts:
                   total = 0
               FOR i = 1 TO 12
                   total = total + month(i)
               NEXT i
                     RETURN

     Функции.
     --------
     Существует два типа функций:  стандартные (такие,  как COS и 
LEFT$), определяемые языком программирования и заданные пользова-

телем,  которые могут состоять как из одной,  так и из нескольких 
строк.  Более подробно заданные функции описаны в соответствующих 
разделах Главы 5. "Справочное руководство по ТУРБО БЕЙСИКу.  
     Ниже приведен пример синтаксиса однострочной функции:

     DEF FNidentifier [(parameter list)] = expression
           идентификатор [(список параметров)]

где идентификатор - это заданное пользователем  имя специфическо-
го выражения, список параметров - дополнительная отделяемая запя-
той последовательность одного или более идентификаторов, предста-
вляющих информационные объекты, направляемые функции при ее вызо-
ве во время выполнения программы (не более 16 параметров для  од-
ной функции), выражение определяет обработку данных для получения 
значения возвращаемого (выдавыемого) функцией.  
     Рассмотрим,  например,  метеорологическую программу, которая 
всегда должна преобразовывать градусы Фаренгейта (показываемые на 
экране и вводимые с клавиатуры). Однострочные функции - благо для 
такого типа программ: 

   DEF FNCtoF(degreesC) = (1.8 * degreesC) + 32
   DEF FNFtoC(degreesF) = (degreesC - 32) * .555555

     Для отображения переменной температуры,  которая по соглаше-
нию  всегда  выражается  в величинах Цельсия,  используйте FNCtoF 
читается как "функция Ц в Ф") в любом  операторе,  воспринимающем 
численные выражения; например: 

   PRINT:
         temp = 100
   PRINT FNCtoF(temp)

     Для перевода значений из градусов Фаренгейта в градусы Цель-
сия пользуйтесь FNCtoC: 

   INPUT "Введите сегодняшнюю температуру"
        temp = FNCtoC(th)

     Многострочные  функции  ТУРБО  БЕЙСИКа берут на себя гораздо 
большую роль,  чем разрешено простыми однострочными функциями Ин-
терпретатора Бейсика.  ТУРБО БЕЙСИК позволяет функции распростра-
ниться по нескольким строкам программы и фактически быть  исполь-
зованной  как  подпрограмма,   которая  может  также  и  получить 
значение.  Формальный синтаксис для описания многострочной  функ-
ции следующий: 

   DEF FNидентификатор [(список-параметров)]
 
     [объявления переменных]
  . операторы
  .
   [EXIT DEF]
   [FN имя-функции = выражение]
  END DEF

где идентификатор описывает имя функции,  список-параметров - это 
дополнительный отделяемый запятой список  формальных  параметров, 
представдяющих переменные, передаваемые функии при ее вызове.  
     Чтобы проиллюстрировать это,  рассмотрим многострочную функ-
цию Факториал, лучший друг статистика.  (Может быть, вы вспомните 
из опыта предыдущих занятий,  что факториал положительного целого 
числа n, описанного как n!,  это произведение положительных целых 
чисел меньше или равных n.  
     Например, 6! = 6 * 5 * 4 * 3 * 2 * 1 = 720).
     Факториалы  не  включены  в  набор встроенных математических 
операторов ТУРБО БЕЙСИКа,  но  многострочные  функции  восполняют 
этот пробел: 

     100 DEF FNFactorial#(x%)
     110   LOCAL i%, total#
     120   IF x% < OR x% > 170 THEN FNFactorial# = -1 : EXIT DEF
     130   total# = 1
     140   FOR i% = x% TO 2 STEP -1
     150     total# = total# * i%
     160   NEXT i%
     170   FNFactorial# = total#
     180 END DEF

     FNFactorial  демонстрирует  структуру  многострочной функции 
(номера строк включены,  поэтому мы можем ссылаться на строки  по 
номерам при их обсуждении - они, конечно, необязательны).  
     Описания  функции  ограничены  операторами DEF FN и END DEF; 
делая отступ в два знака перед операторами DEF FN и END  DEF,  мы 
четко очерчиваем эту структуру.  
     Строка 100 присваивает функции имя и,  следовательно, тип (# 
означает двойную  точность).  У  FNFactorial  один  целочисленный 
формальный параметр x%.  
     Строка  110 описывает пару локальных переменных i% и total#.  
Локальные перменные - это временные структуры,  доступные и види-
мые  только  внутри  описания  функции или процедуры (поробно они 
рассмотрены ниже в разделе "Локальные перменные").  
     Строка  120  производит  проверку  аргумента,  передаваемого 
FNFactorial  .  Бессмысленно пытаться найти факториал отрицатель-
ного числа (его просто не существует) или числа  столь  большого, 
что  оно  дает результат,  выходящий за 10^308 - диапазон двойной 
точности (факториалы вырастают очень быстро  -  170!  это  скачок 
7,26 + 308).  В этих случаях следует определять обратное значение 
функции,  как -1 и EXIT DEF.  Программы,  в которых  используется 
FNFactorial,   должны  распознавать,  что  обратное  значение  -1 
представляет состояние ошибки,  и действовать соответствующим об-
разом. (Точно так же 0! определяется как 1).  
     EXIT  DEF  для  функций  то же,  что RETURN для подпрограмм: 
возвращает управление оператору,  вызвавшему функцию.  Так и  хо-
чется использовать для этого RETURN - но не делайте этого!  Обра-
тите внимание,  что EXIT DEF вовсе необязателен,  если только вам 
не нужно вернуться до конца выполнения функции.  
     Строки с 130 по 160 определяют алгоритм для расчета фактори-
алов.  Эта  часть многострочной функции ("тело") может быть сколь 
необходимо большой или малой.  
     Строка  170  определяет  величину,  выдаваемую  FNFactorial, 
присваивая значение имени функции.  Удивительно, но назначение не 
является синтаксическим требованием для описания функции. Если вы 
не произведете назначение  имени  функции,  то  возвращаемая  ве-
личина будет неопределенной.  
     Определение  FNFactorial  завершается  операторм  END  DEF в 
строке 180.  END DEF как и EXIT DEF, возвращает управление опера-
тору,  вызвавшему  функцию  (Оператор END несет,  пожалуй,  самую 
большую нагрузку в синтаксисе ТУРБО БЕЙСИКа - он испльзуется  для 
завершения целого ряда структур.) 
     Вы никогда не задумывались,  сколько комбинаций можно произ-
вести с колодой карт? FNFactorial знает: 

     PRINT FNFactorial#(52)

дает в результате 8.065817517094388E069.
 
     Поскольку FNFactorial определяется как  имеющий  целочислен-
ный формальный параметр,  аргументы с плавающей запятой перед пе-
редачей ему округляются до целых чисел;  например, FNFactorial(2, 
7)  то  же,  что  FNFactorial(3).  Если вы вызовете FNFactorial с 
числом, большим,  чем может быть обработано программой ТУРБО БЕЙ-
СИКа  "Округлить-до-целого" (больше 32767 или меньше -32768),  вы 
получите ошибку "6" при выполнении - Переполнение.  
     Точно так же обрабатываются рагументы для встроенных функций 
ТУРБО БЕЙСИКа, предполагающих целочисленные аргументы;  например, 
LOCATE 2.7^ 1 (НАЙТИ 2.7, 1) переводит курсор на 3-ю строку.  

     Формальные и фактические параметры.
     -----------------------------------
     Переменные,  появляющиеся в списке параметров  при  описании 
функции называются формальными параметрами. Они служат только для 
определения  функции  и полностью отделены от других переменных в 
программе с таким же названием. В качестве иллюстрации рассмотрим 
следующую короткую программу: 

     100 DEF FNArea(x,y) x * y
     110 x = 56
     120 PRINT x, FNArea(2,3),x

     Переменная x в 110 и 120 строках этой программы не связана с 
формальным  параметром  x,  определенным  в функции Area в первой 
строке. При выполнении этой программы x сохраняет свое значение в 
любой части вызова в FNArea: в обоих случаях печатается 56.  
    Значения, поступающие функции при выполнении,  иногда называ-
ют фактическими параметрами.  В последнем примере численные конс-
танты 2и 3 - фактические параметры, переданные FNArea.  Фактичес-
кие параметры вполне могут быть перменными: 

     a = 2: b  = 3
     PRINT FNArea(a,b)

     Типы функций.
     -------------
     Функции  могут  возвращать  любой из четырех численных типов 
(целочисленный, длинный целочисленный, с плавающей запятой с оди- 
нарной и двойной точностью), а также строковый тип.  Тип функции, 
как и тип переменной, определяется ее именем.  В нем используются 
символы описания типов и оператор DEFtype, например: 

     DEF FNIntSquareRoot %(x) = INT(SQR(x))
     PRINT FHIntSquareRoot %(2)
и
     DEF FNRepeatFirst$ (a$) = LEFT$ (a$,1)+a$
     PRINT FNRepeatFirst$(`Hello`)

     Попытка присвоить строковую функцию численной переменной или 
численную  функцию - строковой переменной приводит,  как и следо-
вало ожидать, к ошибке 13: Несоответствие типа.  

     Процедуры.
     ----------                         
     Процедуры - это блоки программы,  заключенные между операто-
рами  SUB и END SUB.  Формальный синтаксис для описания процедуры 
следующий: 

 SUB имя процедуры [(список параметров)] [INLINE]
     [овъявление переменных]
    .
    .операторы
    .
    [EXIT SUB]
 END SUB
  
     Имя процедуры идентифицирует процедуру и может содержать  до 
31  знака,  но оно не должно включаться ни в один другой оператор 
SUB в программе;  список параметров - это необязательный, отделя-
емый запятой,  список формальных параметров, представляющих пере-
менные, передаваемые процедуре при ее вызове.  (не более 16 пара-
метров  для одной процедуры.) INLINE (ВСТРОЕННАЯ) указывает,  что 
процедура содержит изменяющееся количество нетиповых параметров и 
встроенный код Ассемблера  (см.  Приложение  С  "Интерфейс  языка 
Ассемблера").  
     Как  сказано  ниже,  наидолее явное различие между функциями 
процедурами заключается в том,  что процедуры не возвращают  зна-
чения;  но они также и не вызываются изнутри выражения,  не имеют 

типа и не включают присваивания значения имени процедуры.  Проце-
дуры вызываются оператором CALL,  так же как GOSUB вызывает подп-
рограммы.  
     Рассмотрим следующую  программу,  описывающую  и  вызывающую 
процедуру PrintTotal (ПечатьИтого): 

   SUB PrintTotal(a,b,c,d)
      LOCAL total
      total = a + b + c + d
      Print total
   END SUB
        w = 1: x = 2: y = 0: z = 3
   CALL PrintTotal(w,x,y,z)

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

  SUB countZeros(a(1), size, count)
` счетчик возвращает число нулевых элементов в одномерном масси-
` ве a с одинарной точностью, размер которого size + 1 элементов
    LOCAL i
    count = 0
    FOR i = 0 TO size
      IF a(i) = 0 THEN count = count + 1
    NEXT i
 END SUB

     Наличие a(1) в списке параметров определяет первый аргумент
массива CountZero (СчитатьНули) как одномерный.  Он не  говорит,
каков будет размер массива, - это задача второго аргумента: size
(размер); count используется,  чтобы сообщить количество нулевых
элементов в массиве a. Вызов CountZero производится так:

     size = 100: DIM Primes(size)
     GOSUB StrikePrimes
     CALL CountZeros(Primes(), size, primesCount)
     PRINT "There are" primesCount "prime numbers <=" size
     END

     Определения процедур и функций и ход программы.
     -----------------------------------------------       
     Положение определений процедур или функций внутри  программы 
неважно.  Функция  может  быть  определена  в  1  или 1000 строке 
программы независимо от того,  где  они  используются.  При  этом 
необязательно   направлять  ход  программы  через  процедуру  или 
функцию для этапа инициализации (которую необходимо  проводить  у 
однострочных   функций  в  Интерпретаторе  Бейсика).   Компилятор 
заметит определение, где бы оно ни находилось.  
    Кроме того, в отличие от подпрограмм выполнение программы не
может случайно  "попасть" в процедуру или функцию.  Что касается
маршрута выполнения программы,  определения функций  и  процедур
невидимы. Например,  при  выполнении  следующей  четырехстрочной
программы:

    CALL PrintSomething
    SUB  PrintSomething
    PRINT  "Напечатано из  PrintSomething"
    EHD SUB

сообщение появляется только один раз.

     Заметьте:  Определения процедур и функций следует рассматри-
вать как изолированные островки кода.  Но не следует сломя голову 
бросаться в них или из них с помощью операторов GOTO,  GOSUB  или 
RETURN - результаты могут быть непредсказуемы и/или фатальны.  
    Обратите  внимание,  что  ни  описания процедур,  ни описания 
функций не могут быть  вложены;  т.е.  нельзя  определить  другую 
процедуру  или  функцию  внутри  определения данной процедуры или 
функции (хотя они могут  содержать  вызовы  других  процедур  или 
функций).  

     Проверка аргументов.
     --------------------
     В отличие от других компиляторов Бейсик, ТУРБО БЕЙСИК прове-
ряет соответствие числа и типа аргументов в  вызовах  программных 
процедур  и функций числу и типу формальных параметров в соответ-
ствующих определениях. Например, попытка трансляции программы 

    DEF FNDummy(a,b)
    END DEF
    t = FNDummy(3)

приводит к ошибке "Несоответствие Параметра" в 3-ей строке, т.к.
FNDummy требует два аргумента.

             Более сложные аспекты функций и процедур.
             -----------------------------------------

     Передача параметров по значению или ссылке.      -------------------------------------------
     Существуют весьма тонкие,  но очень  важные  различия  между 
функцией  и процедурой,  а понимание этих различий требует знания 
того,  как ТУРБО БЕЙСИК обрабатывает вызовы функции  и  процедуры 
при выполнении программы (см. Таблицу 4-4).  

           Таблица 4-4. Различия между Процедурой и Функцией
    ------------------------------------------------------------
    Действие                 Функции             Процедуры
    ------------------------------------------------------------
    Возвращение значения   Да                  Нет
    Метод вызова           Вызывается изнут-   Используется
                           ри выражений        оператор CALL
    Передача параметра     Передается по зна-  Передается по
                           чению               ссылке и значению
    Переменные по умол-    ОБЩАЯ               СТАТИЧЕСКАЯ
    чанию
    Аргументы массива      Нет                 Да
    ------------------------------------------------------------

     Во-первых, посмотрите на эту короткую программу, описывающую 
и вызывающую функцию CylVol (Объем цилиндра): 

   DEF FNCylVol(Radius, height) STATIC
      FNCylVol = Radius * Radius * 3.14159 * height
   END DEF
   r = 4.7: h =12.1
   vol = FNCylVol(R,h)

     Теперь  представьте себе объем обработки при выполнении этой 
программы.  Сначала нужно назначить значения переменных  R  и  h.  
Затем вызвать FNCylVol,  передавая ей численную информацию по R и 
h.  Но минуточку,  а каким же образом передать функции эту инфор-
мацию?  
     Есть два способа:  (1) использовать 4.7 в качестве радиуса и 
12.1 - высоты;  или (2) использовать перменную R в качестве ради-
уса,  а h - высоты.  Первый называется - передать по значению,  а 
второй - передать по ссылке.  
     Передача по значению означает, что копии аргументов в вызове 
располагаются в памяти временно,  а затем переносятся,  когда не-

обходимо,  в  вызванную  программу.   После  выполнения  процеду-
ры/функции значение из памяти исчезает;  таким образом  оригиналы 
остаются нетронытыми.  
     Передача по ссылке означает, что передается указатель, пока-
зывающий  где (адрес) хранятся данные.  В примере адреса перемен-
ных R и h передаются как параметры.  Вызываемая  программа  может 
затем получить и изменить сами значения.  
     В ТУРБО БЕЙСИКе используются оба способа передачи (их разли-
чия станут вам ясны через минуту).  
     Метод  передачи  по  значению  позволяет  использовать любую 
константу или выражение в  качестве  аргументов.  при  выполнении 
выражение  оценивается и сводится к простому значению,  которое и 
передается функции. Например: 
  
     V = FNCylVol(R,h * 2 + 4.1)

     Методу передачи по значению не составляет труда сообщить h * 
2 + 4.1  функции  FNCylVol.  Выражение  вычисляется  и  результат 
посылается функции.  
     С другой стороны, однако, метод передачи по ссылке, посколь-
ку  он  позволяет  программе обрабатывать значение,  не оперирует 
константами и выражениями (такое выражение,  как h * 2 +  4.1  не 
имеет адреса в памяти, - его имеют только переменные).  Метод пе-
редачи по ссылке действует только если  аргумент  в  процедуре  -
отдельная переменная.  
     Первый закон передачи параметра: Как переменные, так и выра-
жения могут быть переданы методом передачи по значению.  Передача 
по ссылке позволяет посылать только переменные или массивы.  
     Преимущество передачи по ссылке заключается в том,  что про-
цедура,  вызванная  программой,  может изменять значения парамет-
ров,  передаваемых ей и таким образом,  возвращать информацию вы-
зывающей программе.  Поскольку программа, которой переданы данные 
по ссылке, получает и адрес,  она "знает",  где расположена пере-
менная и,  таким образом,  может как считывать,  так и записывать 
ее.  И напротив, программа, которой переменная передана по значе-
нию,  не может изменять исходную переменную,  поскольку не знает, 
где эта переменная расположена.  
     Второй закон передачи параметра:  Переменные,  переданные по 
ссылке могут изменяться вызванной программой;  переданные по зна-
чению - нет.  
     В качестве иллюстрации рассмотрим программу:

     a = 0: d = 2: c = 3
     call add(a,b,c,total)
     print a, total
     END
     sub add(i,j,k,sum) STATIC
        sum = i+j+k
     END sub

     При возврате add переменная total (итого) содержит сумму  a, 
b и c.  (Add можно определить так,  чтобы она меняла значение ка-
жого из своих аргументов;  однако,  поскольку она дает назначение 
только  своему  четвертому  параметру,  - только на total (итого) 
распространено действие при вызове add).  
     Третий закон - это следствие первого и второго  законов  ТБ: 
Аргументы функций передаются по значению;  аргументы процедур пе-
редаются по ссылке и по значению.  
     Это означает, что отдельные имена переменных могут фигуриро-
вать в вызове процедуры и эти  переменные  могут  быть  изменены.  
Если  Вы  хотите передать по значению одиночную переменную проце-
дуре - заключите ее в скобки.  Это заставляет ТБ анализировать ее 
как  выражение.Процедуры  могут также принимать константы и выра-
жения как передачу по значению.  Вызовы функций  могут  принимать 
константы,  переменные и выражения,  но не могут изменять их зна-
чения.  
     Вполне можно сделать присвоение формальному параметру внутри 
определения функции;  фактически очень часто  бывает  удобно  ис-

пользовать  формальнве параметры функции в качестве временных пе-
ременных.  Это,  однако,  не изменяет значение фактического пара-
метра; например: 

     DEF FNDummy(a,b,c)
        a = a+b+c
        PRINT a
     END DEF
     x = 1: y = 2: z = 3
     t = FNDummy(x,y,z)
     PRINT x

     Присвоение формального параметра a функции FNDummy (учебная) 
не влияет на значение переменной x.  
     Поскольку  передача  переменной  функции подрузамевает также 
копирование данных переменных для размещения в локальной  памяти, 
возникают проблемы, если переменная очень большая (т.е.  массив).  
Поэтому ТБ не позволяет передачу переменных типа массив  по  зна-
чению, хотя можно передать отдельные элементы массивов.  

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

                      Основная программа
  EmployeeCount= 10
  n = 1
  GOSUB CalcChecks
  n = n+1

  CalcChecks:
  GOSUB CalcDeductions
  RETURN
                      Подпрограмма
  CalcDeductions:              
     FOR n=1 to EmployeeCount
    .
    .
    .
     NEXT n
  RETURN

  PrintChecks:
    .
    .
    .
  RETURN

     Переменная  n  в подпрограмме CalcDeduction и переменная n в 
основной  программе - это  одно и то же.  В  результате, при воз-
вращении управления основной программе,  n  не хранит 1, установ-
ленную  здесь  ранее  основной  программой,  но  хранит  значение 
EmployeeCount + 1  как  результат  выполнения  цикла  FOR/NEXT из 
CalcDeductions.  
     В соответствии со своим неформальным стилем Бейсик не требу-
ет от вас объявления переменных (т.е.  обозначения где-то в  опе-
раторе, что вы скоро используете такую-то переменную).  Даже если 
вы фанатично отслеживаете все переменные  вашей  программы,  одно 
неверное движение пальца может погубить все.  
     Для  того,  чтобы предупредить эту проблему ТУРБО БЕЙСИК до-
пускает наличие локальных переменных внутри процедур  и  функций.  
В  отличие  от глобальной переменной локальная переменная сущест-
вует только в программе,  в которой она определена.  Одних только 

локальных  переменных вполне достаточно для того,  чтобы навсегда 
отказаться  от   подпрограмм.   Рассмотрим,   например,   функцию 
AddReceipts (СложитьПоступления): 

DEF FNAddReceipts
  LOCAL x,y,total
  FOR x = 1 TO 12
    FOR y = 1 TO 30
      total = total + Receipts(x,y)
    NEXT y
  NEXT x
  FNAddReceipts = total
END DEF

     Поскольку  переменные  x  и  y  описаны  как  локальные  для 
FNAddReceipts,  можно использовать имена переменных x и y в любом 
месте  программы ( программисты с математическим уклоном стремят-
ся использовать x и y для каждой переменной),  не влияя на значе-
ние x и y в FNAddReceipts (или наоборот).  
     Локальные  переменные  функции AddReceipts существуют только 
до тех пор, пока функция вызвана - до и после этой функции их как 
бы не  существует.  В  качестве  иллюстрации  рассмотрим  кодовый 
сегмент, вызывающий FNAddReceipts: 

x = 35
ThisYear = FNAddReceipts
PRINT x

     Тот  факт,  что  имя  x было присвоено и другим переменным в 
процессе расчета значения возврата для FNAddReceipts,  не  влияет 
на  x  в  строках 1 и 3.  С помощью логической операции выделения 
стека, x в FNAddReceipts - это независимая переменная, которая не 
существует после возврата функции.  
     Локальные переменные должны быть описаны до любого выполняе-
мого оператора в процедуре или функции.  Локальные переменные мо-
гут  быть  массивами:  для этого достаточно просто задать размер-
ность массива после объявления его локальным.  

SUB Dummy
  LOCAL a, locArray(50)
  .
  .
  .
  ERASE locArray
END SUB

     Выделение локального массива  автоматически  отменяется  при 
выходе из процедуры или функции.  
     Недостатком локальных переменных является то, что они теряют 
свое  значение  в  промежутках  между содержащими их программами.  
При каждом вызове "хранилище" для них  создается  заново,  и  они 
инициализируются нулем (или пустыми строками). Например: 

SUB Dummy
  LOCAL c
  PRINT c
  c = c + 1
END SUB

     Можно целый день вызывать Dummy и всегда будет печататься 0.  

     Общий атрибут.
     --------------
     Процедуры  и  функции  могут  также  описывать  переменные с 
помощью общего атрибута.  Общая переменная -  антипод  локальной: 
она  "видима"  и  может  использоваться  всей  программой  (такие 
перменные часто называются глобальными).  

DEF FNDummy
  SHARED a
  a = 6
  FNDummy = a
END DEF
PRINT FNDummy, a

     Благодаря указанию SHARED переменная a в FNDummy и  перемен-
ная a в операторе PRINT одинаковы.  
     Неописанные переменные внутри определений функций по умолча-
нию принимаются за общие;  например в функции AddReceipts,  пока-
занной ранее,  массив Receipts  принят  за  общую  переменную.  В 
определениях процедур по умолчанию массив - СТАТИЧЕСКИЙ (STATIC). 
Мы  настоятельно  рекомендуем,  однако,  четко  описывать  каждую 
переменную, появляющуюся в опеределении функции или процедуры.  

     Статические переменные.
     -----------------------
     Статические переменные - переход между локальными  и  общими 
переменными.  Как и локальная, статическая переменная не мешает в 
программе другим переменным, имеющим такой же идентификатор - она 
видна только изнутри процедуры или функции, описывающей ее. Как и 
общая переменная, статическая переменная занимает постоянное мес-
то в памяти и, таким образом, не теряет свое значение между вызо-
вами процедуры или функции.  Она инициализируется нулем или "пус-
той" (в случае строк) только при начале выполнения программы.  

SUB Dummy STATIC
  STATIC i
  i = i + 1
  PRINT i
END SUB
i = 16
CALL Dummy
CALL Dummy
PRINT i

     Статическая  переменная  i в Dummy отлична от переменной i в 
"основной программе".  Однако, в отличие от локальной переменной, 
она  сохраняет  свое значение между вызовами содержащей ее проце-
дуры.  Она начинается с 0, как и любая другая переменная,  и уве-
личивается вдвое двойным вызовом Dummy.  
     Правильное  использование  аргументов и локальных переменных 
поможет сделать процедуры и  функции  полностью  независимыми  от 
программы,  в  которой они появляются.  Используя концепцию ТУРБО 
БЕЙСИКа "основной файл / рабочий файл" и  метаоператор  $INCLUDE, 
эти  процедуры и функции можно без труда передавать в новые прог-
раммы.  

     Рекурсия.
     ---------
     ТУРБО  БЕЙСИК  обеспечивает  рекурсию  - процесс,  с помощью 
которого функция или процедура вызывает себя, прямо или косвенно. 
Познакомьтесь с рекурсивным преобразованием FNFactorial: 

DEF FNFactorial#(n%)
  IF n% > 1 AND n% < 170 THEN
    FNFactorial# = n% * FNFactorial#(n%-1)
  ELSEIF n% = 0 OR n% = 1 THEN
    FNFactorial# = 1
  ELSE
    FNFactorial# = -1
  END IF
END DEF

     Одно бросается в глаза сразу:  рекурсивный  алгоритм  короче 
нерекурсивного. FNFactorial была сокращена до одного блока IF без 

локальных переменных.  Краткость - характерная черта  рекурсивных 
программ.  
     Другая черта рекурсивного кода - кажущаяся сложность. Лучший 
способ узнать рекурсивный алгоритм - проработать  с  каранашом  и 
бумагой  несколько пробных программ.  Давайте определим факториал 
3,  мысленно  пробежав  по  спирали,   которую совершит программа 
ТУРБО БЕЙСИК, если ей задать оператор 

PRINT FNFactorial#(3)

     Для начала аргумент 3 передается функции по значению. Первым 
делом  FNFactorial  удостоверяется,  что этот аргумент больше 1 и 
меньше или равен 170;  3 проходит это испытание, поэтому выполня-
ется оператор, управляемый первым предложением THEN: 

FNFactorial# = 3 * FNFactorial#(2)

     Этой  строкой  имени  функции присваивается значение 3 (пока 
все хорошо),  помноженное на значение FNFactorial(2),  каково  бы 
оно  ни  было.  Прежде чем присвоение состоится,  следует еще раз 
вызвать FNFactorial,  теперь уже с аргументом 2.  Отложим пока  в 
сторону этот оператор присвоения; вернемся к нему позднее.  
     Второй  вызов  FNFactorial получает аргумент 2 и выполняется 
нормально.  И вновь она удостоверяется,  что аргумент больше 1  и 
меньше или равен 170;  мы вновь оказываемся у рекурсивного опера-
тора: 

FNFactorial# = 2 * FNFactorial#(1)

     Отложите в сторону и этот  оператор  присвоения  и  вызовите 
FNFactorial в третий раз, теперь с аргументом 1.     
     FNFactorial(1) очень легко представить - он определяется как 
1 во втором предложении THEN.  В этот раз,  наконец,  FNFactorial 
разрешено "отдать" значение,  и она отдает значение 1  последнему 
отложенному вызову FNFactorial.  Разрешено также закончить выпол-
нение его оператору присвоения: 

FNFactorial# = 2 * 1

     Этим промежуточным вызовом  полной  FNFactorial  значение  2 
возвращается  исходному  вызову FNFactorial и первому оператору -
продолжению: 

FNFactorial# = 3 * 2

     После этого последнего  присвоения  управление  возвращается 
оператору PRINT и на экране появляется "6".  
     Не  существует однозначного ответа,  когда же следует приме-
нять рекурсию, но в общем,  используйте ее,  когда проблема носит 
"рекурсивный" характер.  Факториалы,  например, иногда рекурсивно 
определяются в математических учебниках: 

     Для любого положитеьного целого числа n,
если n > 1, то
  n! = n * (n-1)!
иначе
  n! = 1

     Использование рекурсивного  алгоритма,  возможно,  потребует 
увеличения исполнительного стека программы с помощью метаоперато-
ра $STACK,  поскольку каждый уровень рекурсии может  занимать  до 
125  байт  (эта  величина меняется).  Для определения оставшегося 
свободного объема стека используйте функцию FRE(-1).  
















Яндекс цитирования