Шрифт
<b><i>Вычисление суммы и произведения.</i></b>
Play

Вычисление суммы и произведения.

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

Пример: сложить первые 10 натуральных чисел

Do i=1,10 ! (по кол-ву слагаемых)

S = S +i

End do

Пример: вычисление определенного интеграла.

Аналогично с произведением, только перед циклом переменная приравнивается 1.

Определение факториала числа.

Алгоритм: Факториал некоторого числа N равен 1*2*3*. *N. Из формулы видно, что последовательность действий сводится к повторению N раз двух действий:

  • вычисления следующего числа (множителя) по формуле i=i+1;
  • умножения предыдущего результата на множитель.

Программа для разбора строки на правильное кол-во скобок

Вводит строку и проверяет, равняется ли количество открывающих скобок количеству закрывающих.

!a code fragment to check for balanced parentheses:

CHARACTER (80 ) : : LINE

SCAN_LINE: DO I = 1, 80

CHECK_PARENS: SELECT CASE (LINE (I :I ))

LEVEL = LEVEL + 1

LEVEL = LEVEL - 1

PRINT *, 'UNEXPECTED RIGHT PARENTHESIS'

! Ignore all other characters

END SELECT CHECK_PARENS

END DO SCAN_LINE

Найти квадратный корень числа А по итерационной формуле Ньютона

Yn +1 =1/2*( Yn + A / Yn ), Y 0 =А

с заданной точностью.

Неправильный вариант 1

Real x , y , yn , eps

Print *,’enter x,eps’

If (abs(yn-y)>eps) exit

Правильный вариант 2

Real x , y , yn , eps

Print *,'enter x,eps'

If (abs(yn-y)<eps) exit

Найти 2 отличия:

1) в операторе Yn =1/2*( y + x / y ) при вычислении 1/2 ==0! Можно использовать 1./2 или 0.5.

2) If ( abs ( yn - y )> eps ) exit – истинно всегда!

Проверку можно было организовать исходя из смысла задачи - if (abs(x/y-y)<eps) . Но в этом случае больше вероятность получить бесконечную рекурсию.

Вообще говоря, тут нужна проверка на зацикливание, так как процесс может не сходиться!

Этот алгоритм можно реализовать и в рекурсивной форме.

Написать программу для нахождения значения функции

F ( x )= 1+1/2+1/4+1/8+…+1/(2* i )+… с заданной точностью eps

Значения первых нескольких последовательных приближений функции:

Обозначим значения функции F ( x ) переменной s , а значения очередного члена ряда – h .

Т.к. функция представляет собой сумму, воспользуемся приведенным выше приемом:

Теперь определим, как найти hi .

Тогда получаем следующий алгоритм:

  • инициализация переменных ( S );
  • организация цикла;
  • вычисление i - ого шага;
  • вычисление очередного ( i -ого) приближения функции;
  • проверка на завершение цикла.

Проверка на завершение – определение истинности условия окончания цикла. Определим это условие. Каждый новый шаг цикла приближает нас к точному значению. Тогда можно принять этим условием ( h < eps ).

Теперь переводим на Fortran . Воспользуемся конструкцией бесконечного цикла:

implicit none

integer i

real eps,s,h

print *,'введите точность'

read *, eps

! инициализация

! основной цикл

h=1 ./ (2.* i ) ! лучше 0.5/i

if (h< eps ) exit

Найти значение числа e с помощью ряда

e =1+1/1!+1/2!+1/3!+….1/ n !

e =1+1/1= e +1=2

e =1+1/1+1/2 != e +1/2! – это обычное вычисление суммы

Теперь определим, как находить каждый новый элемент суммы

ei + 1= ei + Si , Si =1/ i ! - можно честно вычислять факториал каждый раз

Но это жутко неэффективно!

Посмотрим, как меняется Si каждый раз:

Si +1= Si / i - вот готовая формула

В программе воспользуемся циклом с предусловием:

! программа вычисления числа e

implicit none

Real e ,S,eps

integer i

print *,'введите точность'

read *, eps

! инициализация

! основной цикл

do while(S> eps )

Print * , i,e -exp(1.)

Определить, кратно ли одно число другому?

Надо вспомнить о преобразовании типов в арифметических операциях (см. раздел об арифметических операциях).

Так как 5/2*2 ->2*2-> 4, кратность можно определить следующим способом

print * ,a ,' kratno ',b

print * ,a ,' NOT kratno ',b

Аналогично можно проверить и с вещественными числами

print * ,a ,' kratno ',b

print * ,a ,' NOT kratno ',b

Здесь мы неявно выделили остаток от деления одного числа на другое

Чтобы выделить остаток от деления а на b , можно воспользоваться следующим приемом

Rem = a - INT ( a / b ) * b

Но это же самое делает встроенная функция mod ( a , b ) .

if (mod(a,b)==0) print*,'число a кратно b'

Сортировка массива

implicit none

real a(10),b,a1(10)

logical :: flag =. true .

! задание начальных значений массива a по датчику случайных чисел

do i =1,10

call random _ number ( a ) ! – заполнить массив случайными числами

! a(i)=REAL(rand(0)) – в стандарте нет функции rand

a 1= a ! сохраним старые значения массива для дальнейшего вывода

do while(flag)

В массиве A (3,5,7) найти максимальное число. Использовать встроенную функцию MAX ( a , b ,…).

Так как массив трехмерный, надо использовать три вложенных цикла:

do i =1,3

end do

Но, так как все элементы располагаются в памяти компьютера последовательно, можно обратиться к памяти, занимаемой массивом A (3,5,7), как к одномерному массиву T (3*5*7). Для этого воспользуемся оператором Equivalence (наложения переменных).

Implicit none

Integer A( 3,5,7),T(3*5*7)

Equivalence ( A( 1,1,1),T(1))

Do i =2 ,3 *5*7

M= MAX( T( i ),M)

End do

Я не рекомендую использовать оператор Equivalence неопытным программистам. С его помощью легко получить ошибки , которые сложно находятся!

Написать программу, которая находит 10 первых простых чисел.

Простыми являются целые положительные числа, которые делятся нацело ТОЛЬКО на 1 и на самих себя.

Исходные данные – собственно, для решения данной задачи никаких исходных данных не нужно.

Составим алгоритм решения. Для его записи я вначале использую некий псевдокод, ключевые слова которого подчеркнуты. Поскольку задача не кажется тривиальной, воспользуемся методом проектирования сверху вниз, т.е. постепенной детализацией. Предположим, что исполнитель может понять и выполнить команды: “проверить на простое число”, и “сохранить число”. Тогда будет справедливой следующая последовательность:

Будем перебирать все положительные целые числа, пока не наберем 10 простых .

Очевидно, что первыми простыми являются числа 1 и 2. Тогда можно начать перебор с 3. Пусть N – текущее целое положительное число. Тогда вариант 1 запишется так:

Пока количество найденных простых чисел меньше 10 повторять:

Если N – простое число Т о сохранить значение N

N = N +1

Жирным шрифтом выделены те действия (команды), которые на самом деле не являются простейшими, т.е. не могут быть выполнены исполнителем. Их придется детализировать. Первое – количество найденных простых чисел. Это не что иное, как некоторое число. Введем для него дополнительную переменную - k . С учетом первых «тривиальных» простых – 1 и 2, первоначальное значение k равно 3.

Пока k не больше 10 повторять:

Если N – простое число Т о:

сохранить значение N под номером k

k = k +1

Конец если

N = N +1

Как осуществить проверку простое число? Ключевым определения простых чисел является слово ТОЛЬКО! Следовательно, проверку можно организовать «от обратного» – если найдется хотя бы одно число m , больше 1, при делении на которое исходного числа N остаток равен 0, то N – не простое. Для этого достаточно перебрать все числа в диапазоне 1… N

Подвариант 3.1

Повторять i =2 до N -1

Если остаток от N / I равен 0 Т о N не простое

« N не простое » - не просто констатация факта. Это новая полученная информация, которая понадобится после этого цикла. Следовательно, ее нужно сохранить, например, в какой-то логической переменной: IsPrime =ЛОЖЬ. Исходя из «презумпции невиновности» перед проверкой предположим, что N – простое. Как только определили, что это не так – можно прекращать проверку – совершенно не важно, сколько еще чисел являются делителями N .

Подвариант 3.2

IsPrime =ПРАВДА

Повторять i =2 до N -1

Если остаток от N / I равен 0 Т о:

IsPrime =ЛОЖЬ

Прекратить повторять

Конец если

Теперь разберемся с командой «сохранить значение N под номером k ». Если мы хотим сохранить все найденные значения N , то нам придется использовать массив (только массив позволяет под одним именем хранить несколько значений одновременно), например, Primes . Тогда мы получаем «сохранить в ячейке массива Primes под номером k », или

Primes ( k )= N

Если собрать все вместе:

Пока k не больше 10 повторять:

IsPrime =ПРАВДА

Повторять i =2 до N -1

Если остаток от N / I равен 0 Т о:

IsPrime =ЛОЖЬ

Прекратить повторять

Конец если

Если IsPrime =ПРАВДА Т о: (комментарий: N – простое число )

Primes( k)=N

k=k+1

Конец если

N = N +1

Поскольку не осталось «темных мест», можно переходить к кодированию, например на Fortran -е. Для этого достаточно заменить ключевые слова моего псевдокода аналогичными ключевыми словами Fortran -а.

implicit none

integer i,k,N

integer Primes(10)

logical IsPrime

IsPrime =.TRUE.

if (mod(N,I)==0) then

IsPrime =.FALSE.

if ( IsPrime ) then

print *, Primes

Любую программу можно улучшать до бесконечности. Эта – не исключение. Можно подумать об эффективности – внутренний цикл нет смысла повторять до N -1.

Задача: найти среднее арифметическое данных, полученных в результате эксперимента.

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

Итак, алгоритм получается следующий:

  1. Ввод исходных данных
  2. нахождение максимального и минимального.
  3. получение новой последовательности без max и min
  4. нахождение среднего

1. Поскольку нам несколько раз надо будет иметь доступ к исх. данным, придется занести их в массив.

real Arr (100)

print *,’ введите количество чисел’

read *,N

print *,’ введите числа ’

do i =1,N

read *, Arr ( i )

end do

Надо добавить описание переменных i , N и сделать проверку вводимых значений N на допустимость. В случае если пользователь ввел недопустимое значение N (больше 100) дадим ему возможность повторить ввод хотя бы 5 раз. Для этого воспользуемся циклом со счетчиком.

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

real Arr (100)

integer i,N

do i =1,5

print *,’ введите количество чисел’

read *, N

if ( i >0 .and. i <=100 ) exit

end do

print *,’ введите числа ’

do i =1,N

read *, Arr ( i )

end do

2. Поиск max и min осуществим перебором всех значений массива. Рассмотрим на примере поиска max :

Рассмотрим последовательность, состоящую из одного числа ( Arr (1)). Оно и есть максимальное. Сохраним его для последующего использования в переменной a _ max .

a _ max = Arr ( 1)

Добавим к последовательности следующий элемент массива и найдем max :

if ( Arr (2)> a_max ) a_max = Arr (2)

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

if ( Arr ( i )> a_max ) a_max = Arr ( i )

Следовательно, выполнив эту операцию N -1 раз, мы получим результат. Для этого воспользуемся циклом :

a_max = Arr ( 1)

do i =2,N

if ( Arr ( i )> a_max ) a_max = Arr ( i )

end do

Для нахождения min надо использовать тот же алгоритм, только использовать другую переменную (назовем ее a _ min ) и при проверке заменить знак > на <. А саму проверку можно осуществить в том же цикле.

real Arr (100) , a _ max , a _ min

integer i,N

do i =1,5

print *,’ введите количество чисел’

read *, N

if ( i >0 .and. i <=100 ) exit

end do

print *,’ введите числа ’

do i =1,N

read *, Arr ( i )

end do

! ищем max и min

a_max = Arr ( 1)

a_min = Arr ( 1)

do i =2,N

if ( Arr ( i )> a_max ) a_max = Arr ( i )

if ( Arr ( i )< a_min ) a_min = Arr ( i )

end do

3. Теперь перенесем все числа из исходного массива Arr в новый (например, Brr ) за исключением a _ max и a _ min .

do i =1,N

if ( Arr ( i )/= a_max .or. Arr ( i )/= a_min ) Brr ( i )= Arr ( i )

end do

не годится по двум причинам. Во-первых, ячейкам массива Brr с номерами, равными номерам ячеек массива Arr , где находились значения, равные a _ min и a _ max , не будет присвоено никаких значений (они будут находиться в неопределенном состоянии). Если возникли сложности с переводом предыдущей фразы на русский язык, можно рассмотреть результат работы этого алгоритма на примере:

Во-вторых, сравнение переменных вещественного типа на равенство – не самая удачная операция. Правильнее сравнивать переменные целого типа. В задаче целыми являются номера элементов. Тогда получим следующий алгоритм:

Найти номера максимального и минимального элемента (запомним их в дополнительных переменных, например n _ min , n _ max );

Переносим в массив Brr ( i ) все элементы из массива Arr ( i ) кроме имеющих номера n _ min , n _ max .

! ищем max и min и их номера

a_max = Arr ( 1)

a_min = Arr ( 1)

n_max =1

n_min =1

do i =2,N

if ( Arr ( i )> a_max ) then

a_max = Arr ( i )

if ( Arr ( i )< a_min ) then

a_min = Arr ( i )

end do

! перенесем в массив Brr

do i =1,N

if ( i /= n_max .and. i /= n_min ) then

Brr ( k)= Arr ( i )

end if

end do

Для второй части нам пришлось воспользоваться дополнительной переменной k , с помощью которой мы явно меняем значение индекса (номера) элемента массива Brr .

4. Нахождение среднего. Надо сложить N -2 элементов массива Brr и разделить на

Sr = Brr ( 1)

do i =2,N-2

Sr = Sr+ Brr ( i )

end do

print *,’среднее значение =’, Sr /( N -2)

В результате получим следующий вариант программы:

implicit none

real Arr (100), Brr (100), a_max,a_min,Sr

integer i,N,n_max,n_min,k

! ввод данных

do i=1,5

print *,' введите количество чисел'

read *,N

if ( i >0 .and. i <=100 ) exit

end do

print *,' введите числа '

do i =1,N

read *, Arr ( i )

end do

! ищем max и min и их номера

a_max = Arr ( 1)

a_min = Arr ( 1)

n_max =1

n_min =1

do i =2,N

if ( Arr ( i )> a_max ) then

a_max = Arr ( i )

if ( Arr ( i )< a_min ) then

a_min = Arr ( i )

end do

! перенесем в массив Brr

do i =1,N

if ( i /= n_max .and. i /= n_min ) then

Brr ( k)= Arr ( i )

end do

! найти среднее

Sr = Brr ( 1)

do i =2,N-2

Sr = Sr+ Brr ( i )

end do

print *,' среднее значение =', Sr /(N-2)

Найти в массиве второй по величине элемент.

Общая структура алгоритма:

2. Нахождение элемента

3. Вывод результата

Первая часть разбиралась уже не раз.

Как всегда вариантов решения задачи много. Например, найти максимальное значение, выкинуть его, снова найти максимальное. Первый цикл для поиска максимального элемента, второй цикл – для копирования в другой массив всех элементов, кроме найденного, третий цикл – для повторного поиска максимального в новом массиве.

implicit none

real ar (10), br (10), m_max,n_max

integer i,j,N

! Ввод массива

print *,’ введите количество чисел’

read *, N

print *,’ введите числа ’

read *, ar ( i )

! Поиск максимума

m _ max = ar ( 1)

n_max =1

if ( m_max < ar ( i )) then

m_max = ar ( i )

end if

end do

! Копирование в соседний массив

if ( i /= n_max ) THEN

br ( j)= ar ( i )

end do

! Повторный поиск максимума

m _ max = br ( 1)

do i =2,N

if ( m_max < br ( i )) m_max = br ( i )

print *, m _ max

Другой вариант – после первого поиска максимума разделить массив на два – с первого элемента до m _ max (не включая его) и со следующего до последнего элемента. Затем найти максимальные элементы в обоих подмассивах и сравнить их. Максимальный из них и будет искомым.

Следующий вариант - сортировка всего массива по возрастанию. Тогда предпоследний элемент и есть искомый.

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

! Поиск максимума

m _ max = ar ( 1)

n_max =1

if ( m_max < ar ( i )) then

m_max = ar ( i )

! Повторный поиск максимума

if ( n _ max /=1) then

m_max = ar ( 1)

m_max = ar ( 2)

if ( n_max /= i .and. m_max < ar ( i )) then

m_max = ar ( i )

print *, m_max

Но и этот алгоритм можно усовершенствовать. Так ли нужен второй цикл?

Попробуем искать сразу и максимальный элемент и второй по величине. Нам придется ввести еще одну переменную m_max1. Для каждого элемента массива ar надо рассматривать два случая: ar ( i ) больше m_max – в этом случае надо заменить значение m_max на ar ( i ); или ar ( i ) больше m_max1 – в этом случае надо заменить значение m_max1 на ar ( i ). Но в первом случае стоит вспомнить, что первоначальное значение m_max – самое большое из найденных и больше m_max1, следовательно, при смене m_max на новое большее значение старое становится вторым по величине и заслуживает запоминания в m_max1.

implicit none

real ar (10), br (10),m_max ,m_max1

integer i,j,N

! Ввод массива

print *,’ введите количество чисел’

read *, N

print *,’ введите числа ’

read *, ar ( i )

end do

! Чуть больше возни с выбором начальных значений

if ( ar (1)> ar (2)) then

m_max = ar ( 1)

m_max1= ar ( 2)

m_max = ar ( 2)

m_max1= ar ( 1)

if ( m_max < ar ( i )) then

m_max1= m_max

m_max = ar ( i )

else if (m_max1< ar ( i )) then

m_max1= ar ( i )

print *,m_max1,m_max

Программа должна вывести адрес числа (задаваемого пользователем) в массиве с помощью дихотомии (составил Мещеряков Д.В.)

Массив содержит числа, отсортированные по возрастанию . Дихотомию еще называют методом половинного деления.

Итак, алгоритм задачи:

0. Начало программы.

  1. Ввод возрастающей последовательности.
  2. Ввод искомого числа.
  3. Поиск заданного значения и его адреса.
  4. Вывод результата.
  5. Завершение программы.
  1. В начало программы можно включить описание переменных и массивов и присваивание им начальных значений.

program D

implicit none

integer Arr (100), m,n,x,a,b,I

  1. Ввод последовательности можно осуществить разными способами, но мы пойдем по самому простому пути.

! Ввод предела последовательности

do while (0> n.or.n >100.or.m>n)

write (*,*) ' Vvedite kollichestvo znachenie N'

read (*,*) n

end do

! Заполнение массива в порядке возрастания (от a до b )

do I=1,n

Arr ( I)=I

end do

  1. Ввод искомого числа адрес которого нам надо найти.

write (*,*) ' Vvedite iskomoe chislo '

  1. Поиск заданного значения и его адреса в массиве.

! Условно разделим наш массив на 2 части. Начало левой части будет присвоено

! переменной а, а конец переменной b .

! Если искомое число не лежит в выбранной части, то берем второй и делим его

! пополам (соответственно началом и концом правой половины массива служат

! значения переменных а и b ).

! Цикл do while предназначен для завершения поиска.

do while ( Arr (a)/= x.and.Arr (b)/=x)

if ( Arr (a)< x.and.x < Arr (b)) then

  1. Вывод результата.

if ( Arr (a)==x) write (*,10) Arr (a), x,a

if ( Arr (b)==x) write (*,10) Arr (b), x,b

10 Format (' Naidenoe =' ,I3,3x ,'Iskomoe X=',I3,3x,'Adress Arr (', I3,')')

5 . Завершение программы.

end program D

Теперь все объединим .

Дано целое число а и натуральное (целое неотрицательное) число n. Вычислить а в степени n

Найти в одномерном массиве упорядоченные по возрастанию подпоследовательности

Например, в массиве со значениями 1,2,3,4,2,7,2,4,5,7, подпоследовательностей 3 - 1,2,3,4; 2,7 и 2,4,5,7. Для решения задачи надо перебрать все числа (цикл). Подпоследовательность заканчивается, когда следующее число меньше предыдущего. Следовательно, надо сравнивать каждое число со следующим. Рассмотрим два варианта решения. Вынесем их в 2 отдельные подпрограммы. Результат работы подпрограмм - одномерный массив, содержащий длины подпоследовательностей. В главной программе возьмем несколько тестовых вариантов массива, и для каждого вызовем обе подпрограммы для сравнения результата.

Написать программу, которая определяет количество несократимых дробей вида p/q среди натуральных (целых положительных) чисел, при условии что p+q<100.

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

do p=1,98 Внутренний цикл можно сделать таким же, и проверять внутри условие p+q<100 do q=2,98 if (p+q>=100) continue Но это не эффективно. Лучше немного подумать о том, как может изменяться вторая переменная. Тогда мы получим 2 цикла: do p=1,98 do q=2,100-p Условие "несократимости" дроби сводиться к нахождению общих делителей числителя и знаменателя. Для этого можно написать подпрограмму. s=0 ! начальное значение счетчика do p=1,98 do q=2,100-p if (hasNOD(p,q)) s=s+1 ! hasNOD - подпрограмма для определения "несократимости" end do end do print *,s end

Подпрограмма будет выглядеть как-то так function hasNOD(a,b) logical hasNOD integer a,b hasNOD=true if ( есть хотя бы 1 общий делитель) hasNOD=false end

Как определить наличие общего делителя? Придется перебрать все числа, меньшие наименьшего из a и b. do i=2,min(a,b) if (mod(a,i)==0 .and. mod(b,i)==0) then hasNOD=false return ! позволяет выйти из программы сразу без перебора всех остальных возможных делителей. end if end do

В результате получим следующее:

Но главную программу можно слегка сократить, если изменить интерфейс подпрограммы:)

Вводится матрица MxN. Упорядочить матрицу, переставляя строки, так чтобы первый столбец был упорядочен по возрастанию значений элементов столбца. Если элементы первого столбца равны, то упорядочить по второму столбцу, и т.д.

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

  1. ищем положительный элемент слева,
  2. ищем отрицательный элемент справа,
  3. переставляем их местами.

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

Но чаще всего рекурсивный вариант требует больше вычислительного времени из-за "накладных расходов", связанных с многократным вызовом подпрограммы и заполнением стека.

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

Программа должна находить факториалы первых 12 чисел (рекурсивный вариант).

Так как надо повторять вычисления факториала 12 раз, воспользуемся циклом со счетчиком:

Вычисление факториала удобно сделать в виде подпрограммы. Интерфейс подпрограммы: подпрограмма получает на входе число, и возвращает факториал этого числа. Так как она должна возвращать одно значение, удобно использовать FUNCTION.

Факториал некоторого числа N равен 1*2*3*. *N. Его также можно представить в виде N!=(N-1)!*N. Если бы мы могли найти (N-1)!, мы бы вычислили результат. Но, в свою очередь, (N-1)!=(N-2)! *(N-1). Так мы дойдем до 3!=2!*3. А 2!==2 - дальше идти не нужно.

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

FACTORIAL = FACTORIAL(N-1) * N

Условием прекращения вызов может быть уменьшение формального параметра N до 2. Для того, чтобы подпрограмма могла вызывать саму себя, ее надо описать с ключевым словом RECURSIVE. Чтобы избежать неоднозначностей, стандарт предлагает для присваивания возвращаемого результата в функции использовать конструкцию RESULT(. ). Тогда появляется следующий вариант подпрограммы ( номера в скобках я поставил только для дальнейшего описания ) : Чтобы понять работу подпрограммы, я вставил отладочную печать - строки 3 и 9. После запуска на экране появляется следующее: Несколько странный результат отладочной печати легко объясняется. После первого вызова функции FACTORIAL(5) в главной программе происходит переход на первый исполняемый оператор (3), который печатает число 5. Затем выполняется условный логический блочный оператор(4), так как условие в скобках истинно, выполняется оператор (5). Это оператор присваивания. Сначала вычисляется арифметическое выражение FACTORIAL(N-1) * N. По приоритету операций, сначала вычисляется функция FACTORIAL(N-1). При этом происходит ее рекурсивный вызов, но со значением фактического параметра N-1. Опять происходит переход на оператор (3), но значение формального параметра N равно 4. При этом печатается число 4. Так продолжается до того момента, когда значение формального параметра N не станет равным 2. При этом логическое выражение в операторе (4) станет равным ложным и не произойдет рекурсивного вызова FACTORIAL. Возвращаемой переменной FCT присваивается значение 2 (оператор 7), печать (оператор 9) и выход из функции. Происходит так называемая раскрутка. При этом продолжает выполняться оператор (5), вызвавший функцию FACTORIAL(N-1). Результат (число 2) умножается на значение формального параметра N, которое к тому моменту было равно 3. Значение возвращаемой переменной FCT становится равным 2*3. Выполняется оператор (9), который печатает Так продолжается до возврата в первый оператор, вызвавший функцию - оператор WRITE (6,*) N,' factorial is ',FACTORIAL(5) главной программы. Он и напечатает Теперь вернемся к исходному заданию и перепишем главную программу:

Нахождение минимального элемента в массиве (рекурсивный вариант).

Программа должна вывести адрес числа в массиве с помощью дихотомии (рекурсивный вариант).

Идея алгоритма изложена в предыдущей задаче. Единственное отличие - рекурсивное исполнение. Для упрощения отсутствует проверка на зацикленность (при отсутствии в массиве искомого числа).

Вычисление квадратного корня (рекурсивный вариант)

Нахождение наибольшего общего делителя двух чисел.

Наибольшим общим делителем двух целых чисел р и q называется наибольшее целое число d, которое делит р на q нацело.

Эта задача имеет много решений. Первое, которое приходит на ум - тривиальное - простым перебором:

Так как нужно найти наибольший делитель, начинаем с максимально большого делителя - min(a,b)/2. Далее в цикле уменьшаем делитель и ищем то значение, на которое одновременно делятся оба числа. Цикл заканчивается на числе2.

Если в цикле не нашли общего делителя, возвращаем "универсальный делитель" - 1.

Но можно воспользоваться более быстрым алгоритмом: Пусть r- остаток от деления р на q. Если r равно 0, то q является наибольшим общим делителем. В противном случае пусть p равно q, затем — q равным r и повторить процесс нахождения остатка от деления р на q.

Эта задача имеет красивое рекурсивное решение:

Нерекурсивная версия того же алгоритма: Следующий вариант несколько короче: Головная программа для проверки работоспособности приведенных выше подпрограмм:

📎📎📎📎📎📎📎📎📎📎