Цикл задаёт повторяющееся преобразование состояния. Его поведение определяется четырьмя элементами: начальным состоянием, условием продолжения, телом и изменением, которое переводит выполнение к следующей проверке. Выбор между for, while и do while следует не из внешнего вида задачи, а из того, известен ли диапазон заранее, проверяется ли условие до первого шага и какое состояние управляет остановкой.
Корректность цикла состоит из частичной корректности и завершимости. Инвариант связывает уже обработанную часть входа с накопленным состоянием: он устанавливается до первой итерации, сохраняется телом и вместе с ложностью условия даёт постусловие. Мера прогресса изменяется в строго определённом направлении и доказывает, что при выполнении предусловий цикл не может продолжаться бесконечно.
Стоимость алгоритма выводится из структуры повторения, а не из времени одного запуска. Постоянное число шагов, линейный проход, последовательное уменьшение размера в несколько раз и зависимые вложенные диапазоны приводят к различным точным счётчикам и классам роста. Машинная арифметика способна нарушить математическую модель цикла: счётчик переполняется, дробный шаг не достигает границы, а численное приближение перестаёт изменяться раньше заданного допуска.
Опора — Раздел 12: циклы, инварианты и завершимость. Дополнительно используются присваивание, составные присваивания, ++ и -- из Раздела 6, числовая модель и допуски из Раздела 7, операции Math из Раздела 8 и безопасный консольный разбор из Раздела 11.
Каждая задача оформляется отдельной консольной программой полным шаблоном курса и компилируется с
<Nullable>enable</Nullable>. Разрешены только конструкции Разделов 1–12. Массивы, коллекции, собственные методы, рекурсия, исключения,DateTime,Stopwatch,Random,LINQи конструкции последующих разделов не используются. Для циклов с численным критерием обязательны содержательный допуск, обнаружение отсутствия прогресса там, где оно возможно, и независимый пределMaxIterations. Если условие требует доказательства, отдельно формулируются предусловия, начальное состояние, мера прогресса, инвариант, его инициализация и сохранение, условие завершения и получаемое постусловие.
База практических заданий
Уровень I. Базовый
Форма цикла, управляющая переменная, начальное значение, конечная граница и правило изменения заданы условием. Число итераций либо его точная формула известны до запуска и не зависят от вводимых по ходу выполнения данных. Требуется без искажения реализовать заданную схему, назвать первый и последний обрабатываемые элементы, вывести точное число шагов и подтвердить указанный инвариант.
1. Полуинтервал индексов: Дано целое . Циклом for вывести индексы полуинтервала
Отдельно подсчитать число выполнений тела, сохранить первый и последний выведенные индексы только при и подтвердить, что число итераций равно . Для объяснить, почему тело не выполняется. Затем в отдельной версии заменить < n на <= n, заранее предсказать новый последний индекс и число итераций и объяснить ошибку на единицу.
2. Обратный отсчёт: Дано . Циклом while вывести последовательность . Управляющая переменная уменьшается ровно на единицу после вывода. Подсчитать итерации и подтвердить формулу . Инвариант перед очередной проверкой: уже выведены все целые от исходного до значения, на единицу большего текущего счётчика.
3. Обязательная первая итерация: Дано . Циклом do while вывести числа от 1 до включительно и вычислить их сумму. До запуска указать число итераций, первый и последний члены. Инвариант после вывода : накопитель равен . Объяснить, почему предусловие позволяет использовать do while без отдельной обработки пустого диапазона и чем его семантика отличается от while.
4. Арифметическая прогрессия: Даны целые первый член , разность и число членов . Циклом for вычислить
без пересчёта текущего члена по формуле на каждой итерации: начать с current = a и обновлять его через current += d. Сравнить сумму с
Потенциально опасные произведения выполнять в long. Инвариант после итераций: накопитель равен сумме первых членов, а current = a + id.
5. Факториал: Дано . Циклом for вычислить в long, начиная с накопителя 1 и множителя 2. Вывести точное число умножений и подтвердить, что оно равно . Инвариант перед итерацией с множителем : накопитель равен . Объяснить роль нейтрального элемента произведения в случаях и .
6. Целая степень последовательным умножением: Даны double baseValue и целый показатель . Выполнить ровно умножений и получить без Math.Pow внутри цикла. Инвариант после итераций:
После цикла сравнить результат с Math.Pow(baseValue, n) по абсолютной разности. Отдельно разобрать и объяснить начальное значение 1.0.
7. Последовательность Фибоначчи фиксированной длины: Для вывести первые чисел , , и вычислить их сумму. Использовать for и только две переменные для соседних членов. Для и не обращаться к несуществующим позициям и не вводить отдельные массивы. Инвариант перед формированием очередного члена связывает две рабочие переменные с соседними числами последовательности, а накопитель — с уже выведенным префиксом.
8. Табулирование без дробного счётчика: Получить таблицу
на отрезке с шагом . Управлять циклом целым индексом , а аргумент каждый раз вычислять как
Накопление x += 0.25 запрещено. До запуска определить точное число строк и значения крайних аргументов. Вывести , и с выравниванием и четырьмя знаками после запятой.
9. Фиксированная серия измерений с пропусками: Дано число наблюдений ; далее программа получает ровно корректных целых значений от 0 до 100, где 0 означает пропуск. Циклом for вычислить число пропусков, количество принятых измерений, сумму, минимум, максимум и среднее только по принятым значениям. После пропуска использовать continue; экстремумы инициализировать первым принятым значением, а не искусственными пределами. Число итераций всегда равно , независимо от числа пропусков. Для серии без принятых значений вывести отдельный итог без деления на ноль.
10. Прямоугольный вложенный обход: Даны rows >= 0 и columns >= 0. Двумя вложенными циклами вывести все пары
в построчном порядке. Для внутреннего цикла сформулировать инвариант обработанного префикса текущей строки, для внешнего — инвариант полностью завершённых строк. Подсчитать число посещений и доказать точную формулу rows * columns. При rows = columns = n указать класс .
11. Треугольный вложенный обход: Дано . Вывести все пары
в лексикографическом порядке: внешний цикл идёт по , внутренний — от до . Подсчитать число пар и сравнить его с
Получить точное число итераций каждого запуска внутреннего цикла и общую сумму. Объяснить, почему зависимая граница уменьшает точный счётчик примерно вдвое, но не меняет класс .
12. Последовательные и вложенные фрагменты: Дано . Первый цикл выполняет элементарных действий, второй — действий прямоугольным вложенным обходом, третий всегда выполняет ровно 100 действий. Реализовать только увеличение трёх отдельных счётчиков, затем вывести их сумму и сравнить с формулой
Объяснить, почему последовательные стоимости складываются, почему фиксированный фрагмент имеет класс и почему общий класс равен .
Уровень II. Продвинутый
Задан требуемый результат или свойство процесса, но не управляющее состояние, форма цикла и момент остановки. Число итераций заранее неизвестно: оно определяется входным потоком, достижением порога, уменьшением состояния или численной сходимостью. Требуется самостоятельно выбрать
for,while,do whileлибо бесконечный цикл с контролируемымbreak, вывести меру прогресса и инвариант и обосновать завершение либо явно ограничить процесс, завершимость которого не следует из предусловий.
1. Повторный запрос числа: Запрашивать целое число из диапазона до первого корректного результата. null, неверный формат и число вне диапазона имеют разные исходы; при null дальнейшие запросы прекращаются, поскольку входной поток завершён. Самостоятельно выбрать do while либо while (true) с break, подсчитать фактически прочитанные строки и объяснить, почему число итераций нельзя определить до запуска. Успешное значение должно использоваться только после подтверждённого разбора и диапазона.
2. Поток измерений до маркера: Читать строки до маркера "stop" или null. Пустую строку и неверный формат целого отвергать через continue; корректное значение является измерением, включая ноль. Для непустого принятого потока вычислить количество, сумму, минимум, максимум и среднее. Экстремумы инициализировать первым принятым значением. Инвариант после каждой принятой строки должен описывать весь принятый префикс, а не число всех прочитанных строк.
3. Первое превышение порога: Даны первый положительный член , неотрицательная разность , положительный порог и предел MaxTerms. Последовательно суммировать арифметическую прогрессию до первого момента, когда сумма станет строго больше , либо до исчерпания предела. Самостоятельно выбрать состояние и форму остановки, сохранить номер первого превышающего члена и различить исходы Exceeded и LimitReached. Инвариант до добавления очередного члена: сумма равна уже обработанному префиксу и не превышала после ни одного более раннего шага.
4. Числовой профиль: Дано неотрицательное значение long. За один проход по десятичным цифрам получить количество цифр, сумму, произведение ненулевых цифр, максимум, минимум, число нулей и разворот. Для исходного нуля принять одну цифру 0. Затем определить, является ли число палиндромом. Самостоятельно выбрать нейтральные значения и сформулировать инвариант, связывающий рабочий остаток, обработанный суффикс исходного числа и все накопители.
5. Алгоритм Евклида: Для двух положительных long найти НОД переходом
до . Подсчитать итерации и доказать:
- инвариант ;
- сохранение неотрицательности;
- завершимость из .
Сравнить число шагов для соседних чисел Фибоначчи и для пары, где одно число делит другое. Обосновать класс без измерения времени.
6. Быстрое возведение в степень: Даны double baseValue и целый показатель . Самостоятельно построить бинарный алгоритм: при нечётном текущем показателе домножать результат на текущую базу, затем возводить базу в квадрат и делить показатель на 2. Использовать инвариант
Подсчитать отдельно умножения результата и возведения базы в квадрат, сравнить их с умножениями последовательного алгоритма и обосновать .
7. Целая часть квадратного корня: Для найти наибольшее целое , для которого
двоичным поиском по диапазону кандидатов. Переполнение mid * mid исключить сравнением mid <= n / mid, отдельно обработав ноль. Самостоятельно определить границы, лучший подтверждённый ответ и инвариант отброшенных областей. Вывести число итераций и обосновать .
8. Геометрический ряд по допуску: Даны , и MaxIterations. Суммировать
рекуррентно, пока модуль первого ещё не добавленного члена не станет меньше либо не будет достигнут предел. Инвариант после добавлений:
Сравнить сумму с и проверить оценку остатка
Различить успешную остановку по допуску и остановку по пределу.
9. Квадратный корень методом Ньютона: Для и повторять
до выполнения
либо достижения MaxIterations. Вывести приближение, остаток , отклонение от Math.Sqrt(a) и число шагов. Проверить отсутствие прогресса условием next == current. Обосновать сохранение положительности и различие критериев по изменению состояния и по невязке уравнения.
10. Метод половинного деления: Найти корень на . Сохранять замкнутый отрезок, на концах которого значения имеют разные знаки, и делить его пополам до длины не больше , отсутствия прогресса или MaxIterations. До запуска получить верхнюю оценку числа шагов как минимальное , для которого
Сформулировать инвариант локализации корня и меру прогресса — длину интервала.
11. Суммарная длина двоичных записей: Для каждого от 1 до внутренним циклом последовательного деления рабочей копии на 2 определить число двоичных разрядов и прибавить его к общему счётчику. Строки не строить. Связать результат внутреннего цикла с
как математической формулой, не вызывая логарифм в коде. Получить
Для вывести точную сумму по блокам одинаковой длины.
12. Пары делимости: Для каждого от 1 до перебрать положительные кратные и подсчитать пары , где . Доказать точный счётчик
Через сравнение с гармонической суммой получить . Объяснить, почему оценка формально является верхней, но скрывает реальную структуру зависимых границ.
Уровень III. Экспертный
Исследуется не прикладной результат, а граница семантики или доказательства цикла. До запуска требуется предсказать последовательность состояний, достижимость условия остановки, точное либо асимптотическое число шагов и возможное нарушение инварианта. После запуска наблюдение связывается с порядком вычисления, переполнением, конечной точностью и положением
break,continueили изменения управляющего состояния. Защитный предел используется только для безопасного эксперимента и не считается доказательством завершимости.
1. Границы, инкремент и ошибка на единицу: Исследовать схемы:
for (int i = 0; i < n; i++)
for (int i = 0; i <= n; i++)
for (int i = 1; i <= n; ++i)
for (int i = n; i > 0; i--)
for (int i = 0; i < n; i += k)
for (int i = 1; i < n; i *= 2)
Для каждой до запуска вывести первый и последний обрабатываемые элементы и точное число итераций при заданных и , затем подтвердить отдельным счётчиком. Сравнить i++ и ++i в секции изменения for, где значение выражения отбрасывается, и в выражениях sum += i++ и sum += ++i, где результат используется. Объяснить связь границы, момента изменения и ошибки на единицу.
2. Переполнение управляющей переменной: Исследовать отдельно:
for (byte i = 250; i <= 255; i++)
{
Console.WriteLine(i);
}
и
for (int i = int.MaxValue - 2; i <= int.MaxValue; i++)
{
Console.WriteLine(i);
}
Добавить независимый аварийный счётчик, не изменяющий исследуемую переменную. До запуска предсказать значения после достижения максимума в обычном unchecked-контексте и объяснить, почему математически конечный диапазон превращается в незавершающийся цикл. Затем повторить изменение счётчика в checked и зафиксировать исключение в отдельном запуске без try/catch. Сформулировать предусловие, при котором обычное доказательство меры прогресса действительно применимо к конечному машинному типу.
3. Дробный счётчик и недостижимая граница: Начать с double x = 0.0 и десять раз выполнить x += 0.1, выводя G17. Сравнить итог с 1.0. Затем исследовать циклы с условиями x != 1.0 и x < 1.0, ограничив их независимым аварийным счётчиком, и каноническую версию с целым индексом и вычислением x = i * 0.1. До запуска предсказать число итераций; после объяснить двоичную непредставимость шага, накопление ошибки и различие равенства, диапазона и вычисления значения из целого индекса.
4. break, continue и потеря прогресса: Сравнить три программы. Первая использует for, пропускает кратные трём через continue и суммирует остальные числа от 1 до . Вторая реализует то же через while, но располагает i++ после возможного continue; для безопасного запуска используется отдельный предел. Третья содержит два вложенных цикла и выполняет break во внутреннем при первом , для которого . До запуска составить трассы для малых входов. Объяснить, почему continue в for всё равно приводит к секции изменения, почему в while он способен уничтожить меру прогресса и почему break завершает только ближайший цикл.
5. Лаборатория асимптотики: Реализовать шесть фрагментов, каждый из которых только увеличивает счётчик элементарной операции:
- фиксированные
100действий; - один проход длины ;
- последовательное деление положительного значения на
2; - прямоугольный проход ;
- внешний проход с внутренним делением текущего индекса на
2; - перебор кратных из задачи II.12.
Для вывести счётчики. Получить точные формулы либо двусторонние оценки и классифицировать фрагменты как , , , и . Соединить линейный и квадратичный фрагменты последовательно и объяснить сложение стоимостей. Отдельно указать, почему счётчик абстрактных операций подтверждает порядок роста, но не сравнивает реальное время разных операций и сред выполнения.
6. Недостижимый допуск и застой приближения: Методом половинного деления приближать как корень на . Сравнить критерии:
- ширина отрезка не больше допуска;
- не больше допуска;
- точное равенство
x * x == 2.0.
Для допусков , и использовать MaxIterations и отдельно обнаруживать mid == left || mid == right. До запуска предсказать достижимость критериев; после объяснить конечность множества double, округление середины, непредставимость и различие трёх защит: содержательного допуска, обнаружения застоя и предела итераций.
Обязательные контрольные наборы
| Задача | Исходные данные |
|---|---|
| I.1 | |
| I.2 | |
| I.3 | |
| I.4 | , , , |
| I.5 | |
| I.6 | , , |
| I.7 | |
| I.8 | границы и шаг из условия |
| I.9 | , значения 5, 0, 4, 3, 0, 5, 4; затем 0, 0, 0 |
| I.10 | , , |
| I.11 | |
| I.12 | |
| II.1 | "abc", "0", "101", "37"; отдельный запуск с null |
| II.2 | "5", "", "abc", "-2", "0", "stop"; отдельный запуск с null |
| II.3 | , |
| II.4 | 0, 7, 1002001, 1234321, 9_000_000_009L |
| II.5 | , , |
| II.6 | , , |
| II.7 | |
| II.8 | , , |
| II.9 | , , ; MaxIterations = 100 |
| II.10 | , |
| II.11 | |
| II.12 | |
| III.1 | , , , |
| III.2 | начальные значения из условия; аварийный предел 20 |
| III.3 | шаг 0.1; аварийный предел 100 |
| III.4 | , |
| III.5 | |
| III.6 | допуски , , ; MaxIterations = 200 |
Итог модуля
Ученик строит повторение как явную систему «начальное состояние → условие продолжения → тело → изменение», выбирает for, while или do while по природе управляющего состояния и отличает заранее ограниченный диапазон от остановки по данным, порогу или сходимости. Для каждого содержательного цикла формулируются мера прогресса и инвариант, доказываются их инициализация и сохранение и выводится постусловие при завершении. Ученик управляет полуинтервалами и граничными значениями, безопасно применяет break и continue, повторяет консольный ввод, защищает численные процессы допуском, обнаружением застоя и пределом итераций и выводит точные счётчики и классы , , , и из структуры повторения.
Покрытие опоры и границы
for,while,do while, инициализация, условие и изменение: I.1–I.8; самостоятельный выбор формы — II.1–II.10.- Полуинтервалы, первый и последний элементы, ошибка на единицу и заранее известное число итераций: I.1–I.12, III.1.
- Остановка по состоянию, маркеру, порогу и допуску: II.1–II.10, III.3 и III.6.
- Вложенные циклы и зависимые границы: I.10–I.12, II.11–II.12, III.4–III.5.
break,continueи повторный запрос ввода: I.9, II.1–II.3, III.4.- Мера прогресса, инвариант, инициализация, сохранение и постусловие: I.2–I.12, II.2–II.10.
- Точные счётчики и классы , , , , : I.10–I.12, II.5–II.7, II.11–II.12, III.1 и III.5.
- Переполнение счётчика, дробный шаг, недостижимый допуск и отсутствие прогресса: III.2–III.4, III.6.
- Различие асимптотической оценки и фактического времени: I.12 и III.5.
За границей: массивы и коллекции, foreach, собственные методы, рекурсия, генераторы последовательностей, параллельные циклы и измерение производительности через Stopwatch вводятся позднее. Завершимость процессов, не доказуемая в рамках изученной модели, не объявляется установленной только потому, что контрольный запуск закончился; для безопасного исследования применяется явный предел итераций.

