"Предоставим это машине!"

Теперь вы имеете по крайней мере некоторое представление о том, что такое программирование, что такое язык ассемблера, и зачем он нужен. Хотя читателю, возможно, и не терпится, желательно отложить составление программ до конца изучения этого раздела, в котором речь идет о том, что происходит между моментом, когда программист решает: «Предоставим это машине!», и моментом, когда он убеждается, что программа работает.

Последовательность шагов, обсуждаемая ниже и представленная на рис. 3.2, является лишь последовательностью основных указаний. Строго следуйте ей, пока это не войдет в привычку. Опытные программисты делают это инстинктивно, однако иногда бывает полезным разобраться, что же они в действительности делают.

1.       Анализ задачи.

2.      Алгоритм.

3.      Составление блок-схемы.

4.       Составление программы на одном из языков.

5.       Подготовка программы и данных.

6.       Трансляция на машинный язык.

7.      Выполнение.

8.      Проверка и отладка.

Рис. 3.2.

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

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

Затем необходимо решить, стоит ли применение ЭВМ затрачиваемых усилий и средств. Мой личный опыт может служить иллюстрацией. Как-то я принял участие в конкурсе, призом победителю которого являлось путешествие на Гаваи. Правила конкурса были просты: победителем является тот, кто составит из заданных 14 букв наибольшее количество 4-буквенных слов. Несложный подсчет показывает, что всего существует 144 или 38 416 всевозможных 4-буквенных комбинаций из 14 заданных букв. Я составил и пропустил программу, имевшую в качестве входной информации 14 исходных букв и получавшую все возможные буквенные комбинации, всего 2744 строк печатного текста,' содержащих по 14 4-х буквенных комбинаций.

Что же теперь? Было легко отбросить такие комбинации, как СССС. Но что делать с такими, как PITH(или РУТН?) Учитывать ли жаргонные слова? Теперь было необходимо с помощью словаря установить, какие слова являются подходящими, а какие нет. Я слишком поздно понял, что это то же самое, что мне пришлось бы сделать, даже если бы я не использовал ЭВМ для получения всевозможных комбинаций; с ее помощью был подготовлен лишь список буквенных групп. Если бы в распоряжении ЭВМ был список всех допустимых 4-буквенных слов, то она смогла бы полностью выполнить задание. Однако это было не так.

Другими словами, пример, приведенный выше, показывает несостоятельность моего анализа задачи от начала до конца. Если бы я сначала проанализировал задачу, то понял бы, что затраты моего и машинного времени будут напрасными. Миллионы долларов и тысячи человекочасов расходуются каждый год напрасно по этой же причине. Пользователь должен определить, может ли использование ЭВМ дать что-нибудь ему и стоят ли результаты затрачиваемых усилий.

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

Еще одним необходимым предметом анализа является вопрос наличия достаточного количества человеческих и машинных ресурсов. Часто не принимается во внимание то, что расходы на программное обеспечение ЭВМ для решения крупномасштабных проблем превышают расходы на оборудование. Для работы над крупным программным проектом требуется очень большое число программистов. Расходы на организацию их деятельности на время работы над реализацией проекта часто недооцениваются на стадии планирования. Реализация многих проектов была прервана на промежуточной стадии из-за нехватки вычислительных или людских ресурсов. Более тщательный анализ стоящей проблемы обычно позволяет избежать лишних затрат, связанных с отсутствием необходимых условий для начала работы над проектом.

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

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

Расходы на составление собственных программ, возможно, составят значительную часть первоначальных затрат. Но не следует забывать и о затратах на подготовку исходных данных. Предположим, например, что в университете обучается 20000 студентов и каждый из них в среднем прослушивает по 20 курсов лекций. Если для учета посещаемости студентом курса требуется 1 перфокарта, то всего потребуется 400 000 карт, принимая в расчет только студентов, обучающихся в университете в настоящий момент. Отметим, что мы еще не учли студентов, которые могли выбыть из университета по той или иной причине.

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

Предположим, что по окончании подсчета предполагаемых доходов и расходов пользователь все же решил продолжить работу над проектом. Теперь он должен приступить к более детальному изучению проблемы.

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

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

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

Пусть нам заданы 800 чисел, и необходимо вычислить их среднее арифметическое. Процедура вычисления понятна: мы вычисляем сумму и делим ее на 800. Можно внести исходные числа в программу или использовать их в качестве начальных данных. В последнем случае в программу нужно включить цикл, содержащий команды чтения одного числа с перфокарты: Какой же способ предпочтительнее?

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

Изменение одного числа не составит особенного труда независимо от того, внесено ли оно в программу или рассматривается как данные. Но если требуется вычислить среднее арифметическое других 800 чисел? Если числа были внесены в исходную программу, то тогда нам придется ее просто переписать заново для выполнения нового задания. Если же нам заданы 500 списков по 800 чисел, то придется переписать и оттранслировать программу по крайней мере 500 раз. Кажется наиболее простым и экономичным написать одну программу, способную вычислять среднее арифметическое любых 800 чисел и изменять только карты данных, если требуется вычислить среднее новой группы чисел.

Предположим теперь, что мы написали верную программу, вычисляющую среднее арифметическое 800 чисел, набитых на перфокарты и рассматриваемых, как данные. Пусть теперь требуется вычислить среднее 801 числа. Придется ли переписать программу для учета новой ситуации или можно обойтись без этого? Если бы мы более внимательно проанализировали задачу, то мы могли бы предусмотреть подобный случай и написали бы программу, вычисляющую среднее арифметическое любого количества произвольных чисел. Это бы можно было сделать, рассматривая количество чисел как еще одно из данных. Первая карта данных в этом случае информировала бы программу о том, сколько карт нужно прочесть и сколько чисел набито на этих картах. Сами же числа должны были бы располагаться на следующих картах.

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

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

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

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

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

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

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

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

Рассмотрим снова наш пример вычисления среднего арифметического группы чисел. При анализе задачи мы определили, что программа должна:

1.Считать карту данных с информацией о том, сколько всего карт должно быть введено. Пусть это число, т. е. количество чисел, среднее которых требуется подсчитать, равно N.

2.Считать Nкарт.

3.Вычислить сумму введенных чисел.

4.Разделить результат на N.

5.Вывести результат на печать.

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

Графическая интерпретация алгоритма называется блок-схемой. Блок-схема обычно представляет собой набор геометрических фигур Различной формы, изображающих различные машинные операции, соединенные стрелками, указывающими логическую последовательность обработки информации. Изучите приложение 1, если вы не знакомы с техникой составления блок-схем.

 

Рис.3.3. Блок-схема вычисления среднего.

Блок-схема на самом деле является переводом словесного описания метода решения задачи на язык видимых образов. Именно на этой стадии выявляется логическая структура программы. Именно на этой стадии должны быть получены ответы на большинство поставленных выше вопросов. Подробность составления блок-схемы зависит опять же от сложности задачи и от самого программиста. Обычно блок-схема составляется настолько подробно, чтобы обеспечить возможность составления программы простым переводом с «языка блок-схем» на используемый алгоритмический язык.

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

Составление программы с использованием более подробной блок- схемы облегчается по следующим двум причинам: 1) существует хорошая графическая версия составляемой программы, и 2) ее структура уже хорошо продумана на этапе составления блок-схемы. Для начинающего программиста задача составления программы на недостаточно освоенном языке весьма сложна и без дополнительных сложностей планирования программы в процессе ее написания. Поэтому нужно уделять особое внимание составлению блок-схем до начала программирования.

СОСТАВЛЕНИЕ ПРОГРАММЫНА АЛГОРИТМИЧЕСКОМ ЯЗЫКЕ

На этом этапе программист пишет программу на каком-либо символическом языке. К этому моменту надо уже четко представлять себе последовательность команд и все требования программы. ЭВМ не может догадаться о намерениях программиста и выполнить не предусмотренную им работу за него.

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

ПОДГОТОВКА ПРОГРАММЫ И ДАННЫХ

На этом этапе программа и данные подготавливаются для ввода в машину. Если используется ввод с перфокарт, то символическая программа после окончательной проверки набивается на карты. Производятся необходимые предварительные вычисления над данными и их преобразования, после чего данные также перфорируются.

ТРАНСЛЯЦИЯ НА МАШИННЫЙ ЯЗЫК

Мы знаем, что для того, чтобы программа могла выполняться, она должна быть оттранслирована с использованием компилятора или ассемблера. Этот шаг обычно называется шагом компиляции.

ВЫПОЛНЕНИЕ

По командам оттранслированной программы работает CPU, который организует ввод данных, необходимые вычисления и вывод результатов. 

Проделав перечисленные выше шаги, программист теперь может увидеть плоды своих усилий, обычно в форме отпечатанных результатов. Теперь необходимо понять, работает ли программа, выполняет ли она запланированные действия?

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

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

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

Наличие синтаксических ошибок обычно не допускает нормального выполнения программы. Если выполнение программы тем не менее завершилось, результаты все же вызывают сомнение. Нам трудно признать полученные результаты правильными, если известно, что в программе или в данных были отмечены ошибки.

После устранения синтаксических ошибок программист должен исследовать получающиеся результаты для определения правильности работы программы. Если результаты соответствуют ожидаемым, то теперь необходимо начать более тщательную проверку программы. Но что, если результаты не верны? Тогда мы встретились с более неприятным типом ошибок, а именно с логическими ошибками.

Логические ошибки возникают в процессе планирования программы. Где-либо в процессе анализа задачи, составления алгоритма, блок-схемы или при составлении самой программы программистом была допущена смысловая ошибка. Теперь необходимо вернуться назад и заново осмыслить задачу. Учтена ли в алгоритме возникшая ситуация? Правильно ли используются счетчики цикла? Те ли начальные и конечные значения предусмотрены для счетчиков? Имеют ли исходные данные форматы, предусмотренные в программе? Правильно ли обоснованы вычисления? Эти вопросы предстоит решить на данном этапе. Наличие логических ошибок требует перепроверки всех или части пройденных шагов.

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

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

После устранения синтаксических и логических ошибок выходная информация обычно не содержит сообщений о серьезных ошиб-

ках и показывает, что задача решена правильно. Теперь нужно заняться тестированием программы.

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

Тестирование само по себе является искусством. Сам автор программы должен взглянуть на дело глазами пользователя, не знакомого с конкретными деталями использования написанной им программы. Он должен стремиться предусмотреть все возможные случаи применения своей программы и приспособить программу ко всем возможным ситуациям этого применения. Короче говоря, он должен постараться промоделировать с максимальной полнотой все возможные случаи использования своей программы. Более подробно мы изучим вопросы тестирования в гл. 12.

Таким образом, возложение некоторой задачи на ЭВМ требует гораздо большего, чем простое написание программы. Непосредственное программирование составляет лишь малую часть всей необходимой работы. Должное внимание следует уделить анализу стоящей задачи и планированию необходимых действий. После написания программы требуется устранение синтаксических и логических ошибок и тестирование.

{toc_noshowall}

 
Статьи раздела