Функции и процедуры. Математические вычисления. Случайные числа При любой последовательности вычислений ошибки начнут выявляться на том конце, который противостоит началу проверки. Сегодня мы поговорим о процедурах и функциях. Что такое процедура? Это маленькая программа, выполняющая операции с указанными данными. Различают собственно процедуры и функции. Их основное отличие - процедура просто совершает какие-либо операции, а функция обязательно выдаёт какой-либо результат в результате своей работы. Существует огромное количество стандартных процедур и функций. Подпрограммы (так называют процедуры и функции) можно писать и самостоятельно, но об этом речь пойдёт позже. Сейчас нам нужно научиться работать с готовыми функциями. Общие сведения о подпрограммах Фактически, подпрограмма - это такая же полноценная программа, просто работает она не отдельно, не сама по себе, а включена в другую программу. У подпрограммы всегда есть имя. Имя строится по тем же правилам, что и идентифмкатор. Как правило, имена даются вполне логичные. Например, если функция находит максимальное из нескольких чисел, то её логично назвать Max. Подпрограммы могут иметь входные параметры. Входные параметры - это данные, которые сообщаются подпрограмме до начала её работы, а в процессе выполнения эти данные могут использоваться. Тем не менее, подпрограммы могут и не иметь входных параметров. Входные параметры также называют аргументами. Например, функции, которая узнаёт текущее время, никакие дополнительные параметры не нужны, а вот если функция считает факториал, то обязательно должно быть число, для которого он считается. Как было сказано выше, функция выдаёт какое-то значение в результате своей работы. Процедура в общем случае значения не выдаёт. Вызов подпрограмм Вызываются подпрограммы по имени. Если подпрограмме требуется передать какие-либо параметры, то они указываются в скобках после имени подпрограммы через запятую. Если входные параметры отсутствуют, достаточно просто написать имя подпрограммы, либо оставить скобки пустыми. В случае, если работа происходит с функцией, результат можно "сохранить" в какой-то переменной, просто "присвоив" этой переменной функцию. Обратите внимание: работа с функциями происходит как с обычными переменными, просто их значения вычисляются "на лету". Функции математических вычислений Эти функции работают с числовыми данными. Как правило, входным параметром является какое-то число, а выходным результат вычисления. Практически везде аргумент является либо целым числом (Integer), либо вещественным (Real). Возвращаемое значение - тоже число. Рассмотрим некоторые из этих функций: Abs(x) - модуль (абсолютное значение) указанного числа x. Пример: Abs(-5) = 5. Sin(x) - синус числа x. Здесь x - угол в радианах (не в градусах!). Пример: Sin(Pi/2) = 1. Cos(x) - косинус числа x. Аналогично, x - радианы. Пример: Cos(Pi) = -1. Exp(x) - экспонента, ex (e в степени x). Ln(x) - натуральный логарифм числа x. Пример: Ln(Exp(2)) = 2. Sqr(x) - квадрат числа x (x2). Пример: Sqr(5) = 25. Sqrt(x) - квадратный корень числа x. Пример: Sqrt(64) = 8. Int(x) - целая часть числа x. Пример: Int(1.234) = 1. Frac(x) - дробная часть числа x. Пример: Frac(1.234) = 0.234. Round(x) - округление аргумента до ближайшего целого числа. Пример: Round(1.234) = 1. Trunc(x) - целая часть вещественного числа x. Пример: Trunc(1.234) = 1. Pred(x) - предыдущее значение x (например, для x = 2 это 1). Succ(x) - следующее значение x (для x = 2 это 3). Odd(x) - проверка аргумента на нечётность. Функция возвращает значение True, если аргумент является нечётным числом и False - если чётным. Пример: Odd(5) = True. Предсказываю вопрос: в чём отличие Int() от Trunc()? А отличие в том, что Int() возвращает число вещественного типа, а Trunc() - целочисленного. Это лишь часть всех доступных функций. На самом деле их гораздо больше. Но помимо функций есть ещё процедуры. Процедуры работы с числами Поскольку процедуры в результате работы не выдают никакого значения, процедуры работы с числами просто изменяют переданные им параметры-переменные. Inc(x) - увеличение аргумента на единицу. Фактически, это то же самое, что x:=x+1. Тем не менее, рекомендуется использовать именно эту функцию, так как работает она быстрее. Примечание: под понятием "быстрее" подразумевается, конечно, быстрота "компьютерная". Компьютер выполняет миллионы операций в секунду и для человека такие вещи незаметны. Inc(x,n) - увеличение аргумента на число n. Эквивалентно записи x:=x+n. На самом деле, это не две разные процедуры - просто параметр n является необязательным. Да, бывают необязательные параметры, которые можно указать, а можно и не указывать. Если они отсутствуют, то просто берётся какое-то значение по умолчанию. В данном случае n по умолчанию имеет значение 1. Dec(x,n) - уменьшение аргумента на n единиц. Точно также, как и в Inc, параметр n является необязательным. Эквивалентно записи x:=x-n. В документации необязательные параметры обычно заключают в квадратные скобки, т.е. обычно пишут Inc(x , [n]). Обратите внимание: это лишь условное обозначение, которое создано с целью узнавания, что параметр необязательный. В программном коде никаких скобок нет и быть не может. Не хватает стандартных математических функций? Существует дополнительный модуль с именем Math, в котором содержится большое число математических функций. Например, если нужно посчитать гиперболический арксеканс числа, то мучаться и описывать способ его вычисления вручную не придётся есть готовая функция ArcSecH(). Чтобы подключить модуль Math, откройте исходный код модуля. Для этого, когда открыта форма, следует нажать F12, либо выбрать пункт меню View » Toggle Form/Unit. Далее нужно переместиться в самое начала модуля в раздел uses. В этом разделе через запятую описываются имена подключённых модулей. Как можно заметить, даже при наличии пустой формы несколько модулей уже подключены. В этот список и следует добавить Math: Всё, теперь в Вашем распоряжении большое количество математических функций. Пример комбинирования функций Раз уж речь пошла о математических функциях, пусть пример будет на них и основан. Допустим, у нас есть такая сравнительно сложная функция: Нам нужно создать программу, которая бы вычисляла значение этой функции по заданным числам x и y. Рассмотрим поэтапно элементы функции: 1) Возведение числа e в степень, модуль - функции Exp() и Abs() соответственно. 2) Натуральный логарифм - функция Ln(). 3) Число e... Часто спрашивают - как получить число e? Ведь это, по сути, такая же константа, как и число пи... Но она не объявлена... А ответ прост: e = e1, поэтому e - это exp(1). 4) Тангенс - функция Tan(). Всё необходимое у нас есть, поэтому можно приступить к записи. Главное - не забывать заключать в скобки отдельные элементы формулы, чтобы порядок действий сохранился (в нашем примере это не потребуется). var f,x,y: Real; f:=Exp(Abs(x-y))+Ln(1+Exp(1))*Tan(Pi-7); Как возвести число в степень? Почему я останавливаюсь на таких вопросах? Просто они очень часто возникают у новичков и не каждый может догадаться, как выполнить требуемую операцию. Способ 1. Xy можно преобразовать к виду eln(x)⋅y. Тогда возведение в степень можно записать так: := Exp( y * Ln(x) ); Способ 2. В модуле Math есть функция для возведения в степень - Power. У функции 2 аргумента - основание и показатель степени. Запись, соответственно, следующая :=Power(x,y); Случайные числа Зачем нужны случайные числа? Как правило, чтобы проверить результаты какого-то эксперимента при различных условиях. На основе случайных чисел можно вычислять различные вероятности. Во всех языках программирования есть возможность использовать случайные числа. В Pascal (и Delphi соответственно) случайные числа генерируются функцией Random. Функция принимает один параметр, да и тот необязательный... Этот параметр позволяет указать границу диапазона, из которого будет выбрано случайное число. Итак: Random([Range: Integer]). Если Range указан, то число выбирается из диапазона 0 <= X < Range (X само случайное число, которое будет получено). Обратите внимание, что сама граница в диапазон не включается, т.е. Random(10) никогда не выдаст число 10, хотя 0 - запросто. Если диапазон не указан, то он считается равным единице, т.е. 0 <= X < 1. Пример. Создадим форму с кнопкой, но пусть кнопка каждую секунду изменяет своё положение. Воспользуемся таймером (TTimer, вкладка System палитры компонент). Interval оставим без изменения (1 сек.), а вот в обработчике запрограммируем произвольное изменение положения кнопки на форме. Разберёмся, что нам нужно: 1) Позиция кнопки на форме. Как Вы уже знаете, за положение отвечают свойства Left и Top, которые указывают положение левого верхнего угла кнопки относительно левого верхнего угла формы. Именно этим свойствам мы будем присваивать произвольные значения. 2) Каков будет диапазон для генерации случайных чисел? Очевидно, что кнопка не должна уйти за границы формы... Значит нам нужно подключить размеры самой формы, т.е. её высоту и ширину. В данном случае будем использовать не Width и Height, а ClientWidth и ClientHeight, так как в первые свойства входят заголовок и границы формы, а это лишние пиксели, за которые кнопка может вылезти. Однако и это ещё не всё - из этих размеров мы должны вычесть соответственно ширину и высоту самой кнопки, иначе она может частично скрыться за границами. Пишем обработчик: procedure TForm1.Timer1Timer(Sender: TObject); begin Button1.Left:=Random(ClientWidth-Button1.Width); Button1.Top:=Random(ClientHeight-Button1.Height) end; Запускаем программу и наблюдаем... Кнопка действительно прыгает с места на место. Но есть один крайне неприятный момент: запустите программу несколько раз и понаблюдайте за точками, в которые попадает кнопка. Вы сразу заметите, что каждый раз кнопка перемещается по одним и тем же точкам. Отчего это происходит? Дело в том, что числа, выдаваемые функцией Random() на самом деле не являются случайными - они псевдослучайны, т.е. наблюдается повторение. К счастью, решение есть - специальная процедура Randomize() инициализирует генератор случайных чисел, который выдаёт действительно случайные числа. Вызвать эту процедуру нужно всего один раз за время работы программы - обычно это делается при запуске (например, в событии OnCreate формы). Процедура не принимает никаких параметров. Вернёмся к нашему примеру: procedure TForm1.FormCreate(Sender: TObject); begin Randomize end; procedure TForm1.Timer1Timer(Sender: TObject); begin Button1.Left:=Random(ClientWidth-Button1.Width); Button1.Top:=Random(ClientHeight-Button1.Height) end; Теперь кнопка будет прыгать совершенно по разным точкам при каждом запуске программы. Кстати, можно дописать скобки к названию процедуры - от этого работа не изменится: Randomize; = Randomize(); А запись немного красивее (на мой взгляд). Дополнительные возможности редактора кода В редакторе кода есть одна очень хорошая вещь - после того, как написано имя процедуры или функции и открыта скобка, появляется подсказка со всеми параметрами, которые подпрограмма принимает. Более того, там же указаны и типы данных всех параметров. Попробуйте, к примеру, набрать Inc( и подождать секунду - появится подсказка: Как и было отмечено выше, второй параметр является необязательным и он заключен в квадратные скобки. Такие подсказки позволяют моментально узнать, что подпрограмма требует на вход. При этом не придётся открывать модуль, где находится функция, либо искать её описание в документации или справочной системе. Если функции или процедуре входные параметры не нужны, подсказка всё равно появится и сообщит об этом: Если после набора имени и скобки подсказка не появилась, то и при компиляции программы скорее всего возникнет ошибка. Причиной, по которой компилятор не смог найти указанную функцию или процедуру, может быть ошибка при наборе имени, либо модуль, в котором описана подпрограмма, не подключен. Ошибки при компиляции появляются внизу окна редактора кода с указанием номера строки, где обнаружена ошибка и описанием самой ошибки. Попробуем запросить процедуру Randomiz (например, мы случайно недописали букву "e" на конце): Строка с ошибкой выделилась, а внизу появился её номер (28) и описание - Undeclared identifier (неописанный идентификатор). Заключение В этом уроке охвачено сразу несколько тем - знакомство с процедурами и функциями, обзор математических функций и процедур, модуль Math, работа со случайными числами, а также удобства редактора кода и выделение ошибок при компиляции.