Русский

Учебник по MQL4  Операторы  Оператор break

Оператор break


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

Формат оператора break


Оператор break состоит из одного слова, заканчивается знаком ; (точка с запятой).

   break;                                         // Оператор break

Правило исполнения оператора break


Оператор break прекращает исполнение ближайшего внешнего оператора while, for или switch. Исполнением оператора break является передача управления за пределы составного оператора while, for или switch, ближайшему следующему оператору. Оператор break может использоваться только для прерывания выполнения указанных операторов.

Исполнение оператора break можно проиллюстрировать на следующем примере.

Задача 14. Дана нить длиной 1 метр. Требуется сложить нить в форме прямоугольника, имеющего максимально возможную площадь. Путём последовательного перебора вариантов найти площадь этого прямоугольника и длины сторон с точностью до 1 мм.

Из цельного отрезка нити можно сложить бесконечное количество прямоугольников различных размеров. Учитывая, что по условиям задачи точность вычислений составляет 1 мм, мы можем рассмотреть всего 499 вариантов. Первый, самый "тонкий", прямоугольник будет иметь размеры 1 х 499 мм, второй - 2 х 498 мм и так далее, а размеры последнего будут составлять 499 х 1 мм. Нам необходимо перебрать все эти прямоугольники и выбрать из них один, имеющий максимальную площадь.

Легко заметить, что в рассматриваемом наборе прямоугольников встречаются повторяющиеся размеры. Например, первый и последний прямоугольники имеют одинаковый размер: 1 х 499 (то же, что 499 х 1). Аналогично этому, размер второго прямоугольника совпадает с размером предпоследнего и т.д. Нам необходимо составить алгоритм перебора всех оригинальных вариантов, но перебирать повторяющиеся нет необходимости.

Для начала проведём предварительную оценку: определим, как площадь прямоугольника будет зависеть от его размеров. Легко понять, что у первого прямоугольника, с размерами сторон 1 х 499, будет самая маленькая площадь. Далее, по мере увеличения малой стороны, площадь прямоугольников будет увеличиваться. По достижении некоторого значения площади прямоугольников начнут снижаться. Эта зависимость отражена на рис. 44:


Рис. 44. Зависимость размера площади прямоугольника от размера одной стороны.

Глядя на рис. 44, несложно прийти к выводу, что искать максимальную площадь, перебирая варианты, начиная с первого, необходимо лишь до тех пор, пока площадь в процессе вычислений увеличивается. Как только она начнёт снижаться, необходимо закончить перебор и выйти из цикла перебора вариантов. Ниже представлен скрипт rectangle.mq4, в котором реализован такой алгоритм.

//--------------------------------------------------------------------
// rectangle.mq4
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------------
int start() // Специальная функция start()
{
//--------------------------------------------------------------------
int
L=1000, // Заданная длина нити
A, // Первая сторона прямоугольн.
B, // Вторая сторона прямоугольн.
S, // Площадь прямоугольника
a,b,s; // Текущие значения
//--------------------------------------------------------------------
for(a=1; a<L/2; a++) // Заголовок оператора цикла
{ // Скобка начала тела цикла
b=(L/2) - a; // Текущее значение сторон
s=a * b; // Текущее значение площади
if (s<=S) // Выбираем большее значение
break; // Выходим за пределы цикла
A=a; // Запоминаем лучшее значение
B=b; // Запоминаем лучшее значение
S=s; // Запоминаем лучшее значение
} // Скобка конца тела цикла
//--------------------------------------------------------------------
Alert("Максимальная площадь = ",S," A=",A," B=",B);// Сообщение
return; // Оператор выхода из функции
}
//--------------------------------------------------------------------

Проследим, как эта программа работает. В начале программы объявлены и прокомментированы переменные. В пределах цикла for реализуется собственно алгоритм решения задачи. В Выражении_1 задано начальное значение размера стороны а прямоугольника, равное 1. В соответствии с Условием, перебор ведётся до тех пор, пока размер стороны прямоугольника а остаётся меньше половины длины нити. Выражение_2 предписывает увеличивать размер стороны прямоугольника а на каждом шаге итерации.

Переменные a, b и s - текущие переменные, значения которых перебираются. Переменные A, B и S - искомые значения. В начале цикла вычисляется вторая сторона b и площадь s текущего прямоугольника.

      b = (L/2) - a;                   // Текущее значение сторон
s = a * b; // Текущее значение площади

В операторе if проверяется условие выхода из цикла:

      if (s <= S )                     // Выбираем большее значение
break; // Выходим за пределы цикла

Если только что вычисленная площадь текущего прямоугольника s оказывается больше площади S, вычисленной на предыдущей итерации, то это новое значение s и становится лучшим достигнутым результатом. В этом случае Условие оператора if не выполняется, а управление передаётся ближайшему оператору, следующему за оператором if. В этих строках запоминаются лучшие достигнутые результаты:

      A = a;                           // Запоминаем лучшее значение
B = b; // Запоминаем лучшее значение
S = s; // Запоминаем лучшее значение

При достижении ближайшей закрывающей фигурной скобки итерация заканчивается, и управление передаётся в заголовок оператора for для выполнения Выражения_2 и проверки Условия. Если на момент проверки размер стороны а ещё не вырос до указанных пределов, то выполнение цикла продолжится.

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

     if (s <= S )                     // Выбираем большее значение
break; // Выходим за пределы цикла

Действительно, оператор цикла for составлен так, что перебирает все возможные варианты без исключения (половина длины нити L/2 - это сумма двух сторон). В то же время максимальная площадь прямоугольника будет достигнута где-то в середине перебираемого набора вариантов. И как только это событие произойдёт (площадь текущего прямоугольника s окажется меньше или равной ранее достигнутого значения S), в рамках исполнения оператора if управление будет передано оператору break, который, в свою очередь, передаст управление за пределы оператора for в строку:

     Alert("Максимальная площадь = ",S,"  A=",A,"  B=",B);// Сообщение

В результате исполнения встроенной функции Alert() будет напечатана следующая строка:

Максимальная площадь = 62500 А=250 В=250

После этого управление будет передано оператору return, в результате чего специальная функция start() завершит свою работу. Это, в свою очередь, приведёт к окончанию работы скрипта и выгрузке его клиентским терминалом из окна финансового инструмента.

В данном примере оператор break прекращает работу (передаёт управление за пределы) оператора цикла for, а именно того оператора цикла, внутри которого он находится. Ниже приведена функциональная схема цикла for, в котором используется специальный выход:


Рис. 45. Функциональная схема цикла for с использованием оператора break (rectangle.mq4).

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

Возможность специального выхода из цикла в языке MQL4 трудно переоценить. В нашем примере использование оператора break позволило составить алгоритм, при котором выполняются только необходимые вычисления. Алгоритм, составленный без специального выхода из цикла, был бы неэффективным - в этом случае производились бы повторяющиеся вычисления, что привело бы к необоснованной трате вычислительных ресурсов и времени. Заштрихованная область на рис. 44 наглядно показывает область параметров, которые не обрабатывались в рассматриваемой программе (почти половина всех вычислений!), что не помешало получить правильный результат.

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

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

Задача 15. Используя алгоритм Задачи 14, подобрать наименьшую нить, кратную 1 метру, достаточную, чтобы образовать прямоугольник площадью 1.5 м ².

В этой задаче необходимо последовательно перебирать имеющиеся длины нитей, для каждой из которых нужно вычислить максимально достижимую площадь. Решение задачи 15 реализовано в скрипте area.mq4. Варианты решения перебираются в двух циклах - во внешнем и во внутреннем. Внешний цикл перебирает длину нити с шагом 1000 мм, а внутренний находит максимальную площадь для текущей длины нити. В данном случае оператор break используется для выхода из внешнего и внутреннего циклов.

//--------------------------------------------------------------------
// area.mq4
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------------
int start() // Специальная функция start()
{
//--------------------------------------------------------------------
int
L, // Длина нити
S_etalon=1500000, // Заданная площадь (мм2)
S, // Площадь прямоугольника
a,b,s; // Текущие стороны и площадь
//--------------------------------------------------------------------
while(true) // Внешний цикл по длинам нити
{ // Начало внешнего цикла
L=L+1000; // Текущее значение нити в мм
//--------------------------------------------------------------------
S=0; // Начальное значение..
// ..для каждого размера
for(a=1; a<L/2; a++) // Заголовок оператора цикла
{ // Начало внутреннего цикла
b=(L/2) - a; // Текущие значения сторон
s=a * b; // Текущее значение площади
if (s<=S) // Выбираем большее значение
break; // Выход из внутреннего цикла
S=s; // Запоминаем лучшее значение
} // Конец внутреннего цикла
//--------------------------------------------------------------------
if (S>=S_etalon) // Выбираем большее значение
{
Alert("Подходит нить длиной ",L/1000," м.");// Сообщение
break; // Выход из внешнего цикла
}
} // Конец внешнего цикла
//--------------------------------------------------------------------
return; // Оператор выхода из функции
}
//--------------------------------------------------------------------

Здесь внутренний цикл работает подобно тому, как и в решении предыдущей задачи. Оператор break используется для выхода из цикла for, когда достигнуто максимальное значение площади для нити заданной длины. Необходимо особо подчеркнуть, что оператор break, указанный во внутреннем цикле for, передаёт управление оператору, следующему за закрывающей фигурной скобкой цикла for, прекращая таким образом работу цикла. Это явление не оказывает никакого влияния на исполнение внешнего оператора цикла while.

В момент, когда срабатывает оператор break во внутреннем цикле for, управление передаётся оператору if:

   if (S >= S_etalon)                              // Выбираем большее значение
{
Alert("Подходит нить длиной ",L/1000," м.");// Сообщение
break; // Выход из внешнего цикла
}

В операторе if производится проверка: является ли найденная площадь больше или равной заданному по условию задачи минимально допустимому значению 1.5 м 2? Если это так, то решение найдено, и продолжать вычисления нет смысла; управление передаётся в тело оператора if. Исполняемую часть оператора if составляют всего два оператора, первый из которых выводит на экран сообщение о найденном решении:

Подходит нить длиной 5 м.

С помощью второго оператора - break - осуществляется выход из внешнего цикла while и последующий выход из программы. Ниже представлена функциональная схема алгоритма, реализованного в программе area.mq4.


Рис. 46. Функциональная схема программы, в которой реализуется возможность специального выхода из внутреннего и внешнего цикла (area.mq4).

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

Обратите внимание, Условием в заголовке внешнего цикла while является (true), т. е. запись, не содержащая переменной, значение которой в процессе выполнения программы могло бы измениться. Это значит, что выход из цикла while по Условию, указанному в заголовке, никогда не произойдёт. В этом случае использование оператора break является единственной возможностью для выхода из цикла.

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

Использование оператора break для передачи управления за пределы оператора switch рассматривается в разделе Переключатель switch.