Знакомство с языком Erlang, средой исполнения программ на языке.
\section{Задание на часть 1}
\begin{enumerate}
\item Сделайте модуль с именем \code{fib}, в файле \code{fib.erl}.
\item Создайте, не используя хвостовую рекурсию, функцию \code{fib_p} которая получает один аргумент \code{N}, и возвращает \code{N}-е значение последовательности Фибоначчи.
\item Создайте другую функцию без хвостовой рекурсии \code{fib_g} по той же спецификации, используя сторожевые последовательности.
\item Создайте третью функцию \code{tail_fib} по той же спецификации, но с хвостовой рекурсией. (Для хвостовой рекурсии понадобится вспомогательная функция).
\end{enumerate}
\section{Выполнение}
\subsection{Сопоставление с образцом}
Код выполненной лабораторной работы возможно найти по ссылке на \href{https://git.iovchinnikov.ru/ivan-igorevich/erlang-labs}{репозиторий}. Работа выполнена на двух устройствах (с синхронизацией работы через репозиторий):
Основные синтаксические конструкции, использованные при написании функций взяты из материалов к лабораторной работе, со слайда 1-27 презентации. Код написанного модуля, вычисляющего число Фибоначчи приведён в листинге \hrf{lst:fib-p}, код юнит-теста написанного модуля в листинге \hrf{lst:fib-p-test}, а снимок экрана, демонстрирующий успешность пройденных тестов на рисунке \hrf{pic:fib-p-pow}.
\subsection{Сторожевая последовательность и ключевое слово \code{when}}
Основные синтаксические конструкции, использованные при написании функций взяты из материалов к лабораторной работе, со слайда 1-28 презентации и из \href{https://www.erlang.org/doc/getting_started/seq_prog.html#matching,-guards,-and-scope-of-variables}{документации} к языку.
Код написанного модуля, вычисляющего число Фибоначчи с помощью сторожевой последовательности приведён в листинге \hrf{lst:fib-g}, код юнит-теста написанного модуля в листинге \hrf{lst:fib-g-test}, а снимок экрана, демонстрирующий успешность пройденных тестов для обеих функций на рисунке \hrf{pic:fib-g-pow}.
Основные синтаксические конструкции, использованные при написании функций взяты из материалов к лабораторной работе, со слайда 1-31 презентации и из \href{https://ru.wikipedia.org/wiki/Хвостовая_рекурсия}{статьи} в Wikipedia.
Код написанного модуля, вычисляющего число Фибоначчи с помощью сторожевой последовательности приведён в листинге \hrf{lst:fib-g}, код юнит-теста написанного модуля в листинге \hrf{lst:fib-g-test}, а снимок экрана, демонстрирующий успешность пройденных тестов трёх функций на рисунке \hrf{pic:fib-g-pow}.
Основные синтаксические конструкции, использованные при написании функций взяты из \href{https://www.erlang.org/doc/man/timer.html#tc-3}{документации} к языку и \href{https://www.tutorialspoint.com/erlang/erlang_loops.htm}{статьи}.
Код функций, вычисляющих время исполнения функций приведён в листинге \hrf{lst:fib-time}, снимки экрана, демонстрирующие время выполнения функций рисунке \hrf{pic:fib-t-time}.
\item Начиная с\code{N = 20} увеличивать \code{N}с шагом \code{5} до тех пор, пока вычисление \code{fib_p(N)} будет занимать меньше пяти секунд. При каком \code{N} это условие перестает выполняться? Почему так происходит?
Время исполнения превышает \code{5} секунд при подсчёте 30-го значения Фибоначчи. Это происходит, потому что при прямом подсчёте чисел Фибоначчи рекурсивным способом происходит повторное вычисление каждого числа, входящего в состав вычисляемого и дерево рекурсивных вызовов разрастается квадратично.
\item Сколько времени тратится на вычисление \code{tail_fib(10000)}? Почему?
На вычисление 10000-го значения Фибоначчи функцией с хвостовой рекурсией тратится значительно меньше времени (1,371 сек), поскольку функция переиспользует вычисленные на ранних этапах значения для вычисления каждого следующего, что делает её больше похожей на простой цикл в процедурном программировании.
\end{enumerate}
\section{Задание на часть 2}
Квадраты простых чисел и функция Мёбиуса
\begin{enumerate}
\item Создайте модуль с именем \code{mobius}, в файле \code{mobius.erl}.
\item Создайте функцию \code{is_prime}, которая получает аргумент \code{N} и возвращает \code{true}, если число простое или \code{false}, если число не является простым.
\item Сделайте функцию \code{prime_factors}, которая получает аргумент \code{N} и возвращает список простых сомножителей \code{N}.
\item Сделайте функцию \code{is_square_multiple}, которая получает аргумент \code{N}, и возвращает \code{true}, если аргумент делится на квадрат простого числа или \code{false}, если не длится.
\item Наконец, сделайте функцию \code{find_square_multiples(Count, MaxN)}. Эта функция получает \code{Count} -- длину последовательности чисел делящихся на квадрат простого числа, и \code{MaxN} -- максимальное значение, после которого надо прекратить поиск.
\begin{itemize}
\item Если функция находит \code{Count} чисел подряд, делящихся на квадрат простого числа в диапазоне \code{[2, MaxN]}, она должна вернуть первое число из этой последовательности.
\item Если функция не находит серию из \code{Count} чисел делящихся на квадрат простого числа в этом диапазоне, она должна вернуть атом fail.
\item\label{item:task-work} Найдите первый ряд из чисел делящихся на квадрат простого числа длиной 4, длиной 5, и длиной 6. Нужно выбрать значение \code{MaxN} равное 30000. Программа должна завершить вычисления в пределах одной минуты.
Функция последовательно перебирает все числа от «корня из искомого + 1» до 2, возвращая ложь при $N < 2$. Если найдено число, остаток от деления на которое искомого даёт 0 -- искомое не считается простым. В работе используется встроенная в язык функция \code{trunc()}, отсекающая дробную часть передаваемого в аргументе числа.
Код функции приведён в листинге \hrf{lst:is-prime}, сниок экрана, демонстрирующий корректность выполнения функции (с использованием тестов) на рисунке \hrf{pic:is-prime}. Во время работы также была написана функция для проведения ручного тестирования, представленная на рисунке \hrf{pic:say-prime}, демонстрирующем, что число 1111 не является простым..
Функция имеет ограничение и выполняется только для тех чисел, на которые делится без остатка исходное (\code{when X rem N == 0}) с 2 до искомого, складывая в список все значения, меньшие, чем «корень из искомого + 1». Код функции приведён в листинге \hrf{lst:prime-factors}, сниок экрана, демонстрирующий корректность выполнения функции на рисунке \hrf{pic:prime-factors}.
\subsection{Функция вычисления делимости на квадрат простого числа}
Функция перебирает список полученных функцией \code{prime_factors} множителей на наличие повторений, последовательно выделяя головной элемент списка и вызывая функцию \code{lists:member}\footnote{\href{https://www.tutorialspoint.com/erlang/erlang_member.htm}{примеры использования функции}}. Для пустого списка функция возвращает ложь. Например, для числа 111 (\hrf{is-sq-mul1}) функция возвращает ложь, а для 10000 (\hrf{is-sq-mul2}) истину. Код функции представлен в листинге \hrf{lst:is-sq-mul}, а результаты проверки представлены на рисунке \hrf{pic:is-sq-mul}
Функция работает с ограничением по длине найденных значений в списке (\code{when length(FoundSquareMultipleNumber) == Count}) и последовательно уменьшает максимальное число до которого нужно выполнять поиск (ищет не с начала, ас конца). Для максимального значения 2 -- нужно прекратить поиск, в этом случае функция выводит атом \code{fail}. Если проверка \code{is_square_multiple(TestNumber)} возвращает истину, число прибавляется (конкатенируется) к списку уже найденных. Код функции представлен в листинге \hrf{lst:find-sq-mul}. Для проверки работы был написан тест с предложенными в методическом пособии значениями (листинг \hrf{lst:sq-mul-test}). Тест пройден успешно (рисунок \hrf{pic:sq-mul-test}).
Для выполнения п. \hrf{item:task-work} был описан цикл, последовательно увеличивающий число находимых множителей. Результат работы цикла с замерами времени приведён на рис. \hrf{pic:final}