| << К разделам |
| Информатика |
| Алгоритмы |
| Теория информации |
| Теория программирования |
| Все статьи |
| Журнал |
| Подписка |
Интернет-Журнал «Потенциал» |
| Авторам |
| Печатные номера |
|
Адрес редакции: 109544, г. Москва, ул. Рабочая, 84, редакция журнала "Потенциал". Телефоны: 787-24-94, 787-24-95, 678-35-86 E-mail: potential@potential.org.ru Главный редактор А.Д. Гладун Шеф-редактор Г.А. Четин Подробная информация Свидетельство о регистрации— СМИ ПИ № ФС 77-19521. Издаётся с января 2005 года. Тираж — 4000 экз, периодичность выхода — раз в месяц Печать — ООО "Азбука-2000" Журнал издаётся на средства выпускников технических вузов ISSN 1814-6422 |
| Полезные сайты |
ЗФТШ
|
МЦНМО
|
Журнал "Квант"
|
"Открытый Колледж"
|
Союз образовательных сайтов
|
Интернет-портал "Абитуриент"
|
| Другие ссылки... |
|
— Голубчики,— сказал Фёдор Симеонович озабоченно, разобравшись в почерках.— Это же проблема Бен Бецалеля. Калиостро же доказал, что она не имеет решения. — Мы сами знаем, что она не имеет решения,— сказал Хунта, немедленно ощетиниваясь.— Мы хотим знать, как её решать. — Как-то странно ты рассуждаешь, Кристо... Как же искать решение, когда его нет? Бессмыслица какая-то... — Извини, Теодор, но это ты очень странно рассуждаешь. Бессмыслица — искать решение, если оно и так есть. Речь идёт о том, как поступать с задачей, которая решения не имеет. Это глубоко принципиальный вопрос... А. и Б. Стругацкие. «Понедельник начинается в субботу»
Профессионал порою сталкивается и с совершенно другой ситуацией. Ему ставят задачу, которая заведомо неразрешима. Но её надо решать (это лишь один из многих подобных случаев в реальной жизни: прочитайте книгу [1]). Что же делать? Решать! Но решать, зная, а не забывая, что она неразрешима. Намеренное либо самоуверенное невежество в данном случае обязательно приведёт к краху.
В своё время автор слышал доклад выдающегося математика (тогда российского) Б. А. Трахтенброта «Как решать неразрешимые задачи?» (1979 г., ныне грузинский, а тогда российский, город Телави). Когда через пару лет автору пришлось составлять обзор по семантике языков программирования, он натолкнулся на французскую статью под лихим названием «Indecidable? Sur pas!» (вольный русский перевод: «Неразрешимо? Наплевать!») И стало ясно, что такие вещи, как решение неразрешимого, формализация неформализуемого и прочее типичны для человеческой деятельности, как и замечали братья Стругацкие устами Кристобаля Хунты.
Если программы не слишком сложные, достаточно всего-навсего выбросить из создаваемого мини-языка программирования циклы while и рекурсивные процедуры (которые, если явно не протестовать, системные программисты ради общности и крутизны обязательно вставят, поскольку «иначе система не будет универсальной»). Тогда всякая программа будет заканчивать работу (просто по построению не даём мы ей возможности зациклиться!). Если системщики вопят, а начальство смотрит на них как на полубогов, то заставьте их хотя бы выдавать для программистов длинные предупреждения типа:
Использование цикла while может привести программу к зацикливанию. Уверены ли вы в том, что нужно использовать цикл while? (ответ No по умолчанию)
А после ответа Yes вдобавок ещё (в лучших традициях игр, из которых Вам хочется выйти побыстрее, чтобы шеф, либо мама, либо преподаватель не застукали, а вам задают кучу вопросов):
В большинстве случаев то, что может сделать цикл while, может сделать и цикл for. Не хотите ли Вы использовать цикл for? (ответ Yes по умолчанию)
И как финальный аккорд нечто типа:
ОК. Ваша программа помечена как не сертифицируемая на корректность. Желаем успехов.
Приведённое решение является частным случаем трёх общих принципов.
Принцип 1. Если нельзя решить задачу в полном объёме, разберитесь, что же на самом деле нужно, и решите частную задачу. Если задачу можно решить в полном объёме, тем не менее подумайте, какого частного случая на самом деле достаточно, и тогда Ваше решение станет намного лучше.1
Принцип 2. Если нечто нужно гарантировать для решения, лучший способ - обеспечить это с самого начала, ещё в ходе построения программы. Потом даже проверить будет трудно, а если ещё вдобавок выяснится, что требование нарушено, то переделывать будет ещё труднее, чем писать хорошо сразу.2
Принцип 3. Если вам не удаётся заблокировать неразумное решение, при помощи технических и бюрократических частностей сделайте так, чтобы пользоваться им было как можно более противно.3
Этот способ решения неразрешимых задач можно проиллюстрировать следующим рисунком. То, что за забором — наши культурные растения, а снаружи все считается сорняками и там мы просто не сажаем.
В частности, если те же программы для собачьих ошейников уже написаны, либо пишутся законченными хакерами, которым хоть кол на голове теши, но от крутизны они не откажутся, то остается посмотреть на данную конкретную совокупность программ и строить алгоритм, который будет работать именно на ней4. Главное, чтобы Ваш алгоритм успешно искал ошибки в конкретных программах, а то, что он в общем случае некорректен, стоит рассматривать как неизбежное зло.
Например, если вы замечаете, что программисты часто опрашивают один и тот же датчик, не проведя повторного измерения, то такую ошибку можно успешно вылавливать и сообщать о ней, скажем, так:
«Давление повторно не измерялось перед очередной его проверкой в строке 1221. Ваша программа зацикливается.»
Схематически можно изобразить такой способ работы на следующем рисунке. То, что за колючей проволокой, по определению считается плохим и отстреливается.
В предыдущих разделах предполагалось, что безвреднее не найти зацикливание, чем найти зацикливание в работающей программе. Но, порою, лучше выдать лишнее предупреждение, чем пропустить заведомо плохой алгоритм. Далее, порою можно допускать ошибки и в две стороны, если цена ошибки не очень высока и в большинстве случаев программа все равно работает правильно. Схематически можно изобразить такой способ работы на следующем рисунке. Здесь граница проведена попроще, но возле её могут быть ошибки в две стороны.
Например, автор пользовался простым, но неправильным, алгоритмом быстрого нахождения возможного (формального либо фактического) зацикливания в программах студентов.
Если цикл встречается внутри рекурсии, либо рекурсия внутри цикла, то процедура написана некорректно.
В подавляющем большинстве случаев это правило действительно указывало на плохо продуманные процедуры, которые, даже если работали для совсем простых входных данных, разваливались на чуть более сложных. Но иногда такой приём оправдан (лично я советую вам таким приёмом не пользоваться; если хочется скрестить рекурсию и цикл, значит, почти наверняка вы плохо продумали структуры данных либо алгоритм).
На самом деле эти приёмы имеют под собой теоретическую подоплёку, которую впервые заметил Б. А. Трахтенброт в уже упоминавшемся докладе. Часто неразрешимая задача превращается в достаточно простую, если мы разрешим ошибаться с малой вероятностью (в принципе даже со сколь угодно малой).
В качестве примера труднейшей (на практике) задачи, решение которой значительно облегчается переходом к случайному алгоритму, рассмотрим следующую, которую автор вместе с группой товарищей по общежитию исследовал ещё в студенческие годы.
Проблема. В стратегических шахматах два шахматиста общаются через судью. Судья единственный, кто знает полное положение на доске. Каждый игрок знает лишь соотношение сил и положение своих фигур.
Судья сообщает игрокам минимально необходимую информацию о ходе. Он произносит примерно такую последовательность фраз в ответ на попытки одного из игроков сделать ход (черные это были или белые, догадайтесь сами):
- Ход невозможен.
- Ход невозможен.
- Ход невозможен.
- Ход сделан. Взята ладья на поле e1. Пешка превратилась в ферзя. Шах.
Первый возможный ход считается сделанным. Причина, по которой невозможен ход (открывается шах, перекрыта линия, король пошёл под удар и т. п.) не объясняется. Стратегические шахматы порождают ряд интереснейших задач, пару из которых (одна из них более простая, вторая — исключительно сложная) приведём сейчас:
Король-всезнайка против ферзя.
Король знает всё, а король и ферзь играют против него по правилам стратегических шахмат. Дать мат.
Король-всезнайка против ладьи.
Король знает все, а король и ладья играют против него по правилам стратегических шахмат. Дать мат.
Во второй задаче достаточно просто дать алгоритм и составить программу, которая будет случайно матовать короля таким образом, что с вероятностью 1 в конце концов его заматует (но теоретически король, если он не только всезнайка, но ещё и прорицатель, знающий будущее, может бесконечно избегать мата). Есть и алгоритм, матующий с гарантией, но он намного сложнее и в разработке, и в реализации.
Желающие могут попробовать поломать голову над задачей и присылать решения автору через редакцию журнала.
Перечисленные методы лишь немногие из тех, которые мог бы предложить его преподобие магистр магии Кристобаль Хозевич Хунта, но автор, конечно же, не может равняться со столь почтенным персонажем, и умолкает.
И напоследок замечание о книге [2], из которой взят эпиграф. Перефразируя античную пословицу, тот, кто её не читал, верблюд. Вообще, фантастика времени расцвета содержит намного больше идей и в большинстве намного интереснее, чем нынешняя штампованная фэнтези (в этом с удивлением убеждались ученики автора, которым он настоятельно советовал почитать «старьё» типа Стругацких, Шекли, Азимова; ещё раз напоминаем, что классика не стареет, и в этом её отличие от поделок).