Эффективность и технологичность



Традиционно эффективными считают программы, требующие минимального времени

выполнения и/или минимального объема оперативной памяти. Особые требования к

эффективности программного обеспечения предъявляют при наличии ограничений (на время

реакции системы, на объем оперативной памяти и т. п.). В случаях, когда обеспечение

эффективности не требует серьезных временных и трудовых затрат, а также не приводит к

существенному ухудшению технологических свойств, необходимо это требование иметь в виду.

Разумный подход к обеспечению эффективности разрабатываемого программного

обеспечения состоит в том, чтобы в первую очередь оптимизировать те фрагменты программы,

которые существенно влияют на характеристики эффективности. Для уменьшения времени

выполнения некоторой программы в первую очередь следует проанализировать циклические

фрагменты с большим количеством повторений: экономия времени выполнения одной итерации

цикла будет умножена на количество итераций.

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

увеличению емкостных и, наоборот, уменьшение объема памяти может потребовать

дополнительного времени на обработку.

И тем более не следует «платить» за увеличение эффективности снижением технологичности

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

требованиях и наличии соответствующего контроля за качеством.

Частично проблему эффективности программ решают за программиста компиляторы.

Средства оптимизации, используемые компиляторами, делят на две группы:

машинно-зависимые, т. е. ориентированные на конкретный машинный язык, выполняют

оптимизацию кодов на уровне машинных команд, например, исключение лишних пересылок,

использование более эффективных команд и т. п.;

машинно-независимые выполняют оптимизацию на уровне входного языка, например,

вынесение вычислений константных (независящих от индекса цикла) выражений из циклов и т. п.

Естественно, нельзя вмешаться в работу компилятора, но существует много возможностей

оптимизации программы на уровне команд.

Способы экономии памяти. Принятие мер по экономии памяти предполагает, что в каких-то

случаях эта память неэкономно использовалась. Учитывая, что анализировать имеет смысл только

операции размещения данных, существенно влияющие на характеристику эффективности, следует

обращать особое внимание на выделение памяти под данные структурных типов (массивов,

записей, объектов и т. п.).

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

алгоритмы обработки, не требующие дублирования исходных данных структурных типов в

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

операцию в заданном массиве, например, хорошо известная сортировка методом «пузырька».

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

можно размещать в динамической памяти и удалять при завершении обработки.

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

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

передавать данные «по ссылке», но как неизменяемые (описанные const). В последнем случае в

стеке размещается только адрес данных, например:

Type Mas.4iv = array [I.. 100] of real;

function Summa (Const a:Massiv; ...)...

Способы уменьшения времени выполнения. Как уже упоминалось выше, для уменьшения

времени выполнения в первую очередь необходимо анализировать циклические участки

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

• выносить вычисление константных, т. е. не зависящих от параметров цикла, выражений из

циклов;

• избегать «длинных» операций умножения и деления, заменяя их сложением, вычитанием и

сдвигами;

• минимизировать преобразования типов в выражениях;

• оптимизировать запись условных выражений - исключать лишние проверки;

• исключать многократные обращения к элементам массивов по индексам (особенно

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

значение индексов) - первый раз прочитав из памяти элемент массива, следует запомнить его в

скалярной переменной и использовать в нужных местах;

• избегать использования различных типов в выражении и т. п.

Рассмотрим следующие примеры.

Пример 2.2. Пусть имеется цикл следующей структуры (Pascal):

for y: = 0 to 99 do

for x: = 0 to 99 do

a [320*x+y]: = S [k,l];

В этом цикле операции умножения и обращения к элементу S[k] выполняются 10000 раз.

Оптимизируем цикл, используя, что 320 = 28 + 26:

skl: =S [k,l]; {выносим обращение к элементу массива из цикла}

for x: = 0 to 99 do (меняем циклы местами}

begin

i:= x shl 8 + x shl 6; {умножение заменяем на сдвиги и выносим из цикла}

for y; = 0 to 99 do

a [i+y]: =skl;

end; ...

В результате вместо 10000 операций умножения будут выполняться 200 операций сдвига, а их

время приблизительно сравнимо со временем выполнения операции сложения. Обращение к

элементу массива S[k] будет выполнено один раз

Модули и их свойства

 Модули. Модулем называют автономно компилируемую программную единицу. Термин

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

сравнительно невелик, и все подпрограммы компилировались отдельно, под модулем понималась

подпрограмма, т. е. последовательность связанных фрагментов программы, обращение к

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

появилась возможность создавать библиотеки ресурсов: констант, переменных, описаний типов,

классов и подпрограмм, термин «модуль» стал использоваться и в смысле автономно

компилируемый набор программных ресурсов.

Данные модуль может получать и/или возвращать через общие области памяти или параметры.

Первоначально к модулям (еще понимаемым как подпрограммы) предъявлялись следующие

требования:

• отдельная компиляция;

• одна точка входа;

• одна точка выхода;

• соответствие принципу вертикального управления;

• возможность вызова других модулей;

• небольшой размер (до 50-60 операторов языка);

• независимость от истории вызовов;

• выполнение одной функции.

Требования одной точки входа, одной точки выхода, независимости от истории вызовов и

соответствия принципу вертикального управления были вызваны тем, что в то время из-за

серьезных ограничений на объем оперативной памяти программисты были вынуждены

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

подпрограммы, имеющие несколько точек входа и выхода, были не только обычным явлением, но

и считались высоким классом программирования. Следствием же было то, что программы было

очень сложно не только модифицировать, но и понять, а иногда и просто полностью отладить.

Со временем, когда основные требования структурного подхода стали поддерживаться

языками программирования, и под модулем стали понимать отдельно компилируемую библиотеку

ресурсов, требование независимости модулей стало основным.

Практика показала, что чем выше степень независимости модулей, тем:

• легче разобраться в отдельном модуле и всей программе и, соответственно, тестировать,

отлаживать и модифицировать ее;

• меньше вероятность появления новых ошибок при исправлении старых или внесении

изменений в программу, т. е. вероятность появления «волнового» эффекта;

• проще организовать разработку программного обеспечения группой программистов и легче

его сопровождать.

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

Степень независимости модулей (как подпрограмм, так и библиотек) оценивают двумя

критериями: сцеплением и связностью.

Структурное программирование

Одним из способов обеспечения высокого уровня технологичности разрабатываемого

программного обеспечения является структурное программирование.

Различают три вида вычислительного процесса, реализуемого программами: линейный,

разветвленный и циклический.

Линейная структура процесса вычислений предполагает, что для получения результата

необходимо выполнить некоторые операции в определенной последовательности.

Разветвленная структура процесса вычислений предполагает, что конкретная

последовательность операций зависит от значений одной или нескольких переменных.

Циклическая структура процесса вычислений предполагает, что для получения результата

некоторые действия необходимо выполнить несколько раз.

Для реализации указанных вычислительных процессов в программах используют

соответствующие управляющие операторы. Первые процедурные языки программирования

высокого уровня, такие, как FORTRAN, понятием «тип вычислительного процесса» не

оперировали. Для изменения линейной последовательности операторов в них, как в языках

низкого уровня, использовались команды условной (при выполнении некоторого условия) и

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

запутанную структуру, присущую в настоящее время только низкоуровневым (машинным)

языкам.

 

 

После того, как в 60-х годах XX в. было доказано, что любой сколь угодно сложный алгоритм

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

программирования высокого уровня появились управляющие операторы для реализации

соответствующих конструкций. Эти три конструкции принято считать базовыми. К ним относят

конструкции:

следование - обозначает последовательное выполнение действий (рис. 2.3, а);

ветвление - соответствует выбору одного из двух вариантов действий (рис. 2.3, б);

 

 Примечание. Слово «структурное» в данном названии подчеркиваем тот факт, что при

программировании использованы только перечисленные конструкции (структуры). Отсюда и

понятие «программирование без go to».

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

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

проектировании или реализации которых использовались низкоуровневые способы передачи

управления.

6. Средства описания структурных алгоритмов

Псевдокоды. Псевдокод - формализованное текстовое описание алгоритма (текстовая

нотация).

Описать с помощью псевдокодов неструктурный алгоритм невозможно. Использование

псевдокодов изначально ориентирует проектировщика только на структурные способы передачи

управления, а потому требует более тщательного анализа разрабатываемого алгоритма. В отличие

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

Они позволяют соизмерять степень детализации действия с уровнем абстракции, на котором это

действие рассматривают, и хорошо согласуются с основным методом структурного

программирования - методом пошаговой детализации.

В качестве примера посмотрим, как будет выглядеть на псевдокоде описание алгоритма

поискового цикла, представленного на рис. 2.6:

i: =1

Цикл - пока i ≥ < n и A[i] ≠ у

i: =i+l

Все - цикл

Если I ≥ n

то Вывести «Элемент найден»

иначе Вывести «Элемент не найден»

Все-если

Flow-формы. Flow-формы представляют собой графическую нотацию описания структурных

алгоритмов, которая иллюстрирует вложенность структур. Каждый символ Flow-формы

соответствует управляющей структуре и изображается в виде прямоугольника. Для демонстрации

вложенности структур символ Flow-формы может быть вписан в соответствующую область

прямоугольника любого другого символа. В прямоугольниках символов содержится текст на

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

вписанного в него текста и размерами вложенных прямоугольников. Символы Flow-форм,

соответствующие основным и дополнительным управляющим конструкциям, приведены на рис.

2.7.

На рис. 2.8 представлено описание рассмотренного ранее поискового цикла с использованием

Flow-формы. Хорошо видны вложенность и следование конструкций, изображенных

прямоугольниками.

Диаграммы Насси-Шнейдермана. Диаграммы Насси-Шнейдермана являются развитием

Flow-форм. Основное их отличие от Flow-форм заключается в том, что область обозначения

условий и вариантов ветвления изображают в виде треугольников (рис. 2.9). Такое обозначение

обеспечивает большую наглядность представления алгоритма.

Также, как при использовании псевдокодов, описать неструктурный алгоритм, применяя Flow-

формы или диаграммы Насси-Шнейдермана, невозможно (для неструктурных передач управления

в этих нотациях просто отсутствуют условные обозначения). В то же время, являясь

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

Общим недостатком Flow-форм и диаграмм Насси-Шнейдермана является сложность

построения изображений символов, что усложняет практическое применение этих нотаций для

описания больших алгоритмов.

7. Правила оформления программ

Стиль оформления программы включает:

• правила именования объектов программы (переменных, функций, типов, данных и т. п.);

• правила оформления модулей;

• стиль оформления текстов модулей.

Правила именования объектов программы. При выборе имен программных объектов следует

придерживаться следующих правил:

• имя объекта должно соответствовать его содержанию, например:

MaxItem - максимальный элемент;

NextItem - следующий элемент;

• если позволяет язык программирования, можно использовать символ «_» для визуального

разделения имен, состоящих из нескольких слов, например:

Max_Item, Next_Itetm;

 необходимо избегать близких по написанию имен, например:

Index и InDec.

Правила оформления модулей. Каждый модуль должен предваряться заголовком, который,

как минимум, содержит:

• название модуля;

• краткое описание его назначения;

• краткое описание входных и выходных параметров с указанием единиц измерения;

• список используемых (вызываемых) модулей;

• краткое описание алгоритма (метода) и/или ограничений;

• ФИО автора программы;

• идентифицирующую информацию (номер версии и/или дату последней корректировки).

Стиль оформления текстов модулей. Стиль оформления текстов модулей определяет

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

Как правило, пропуски строк и комментарии используют для визуального разделения частей

модуля,

 

8. Разработка технического задания.

Техническое задание.

Существует стандарт: ГОСТ 19.201-78

Состоит из разделов:

1Введение — краткая хар-ка облости применения программы. Цель — продемонстрировать актуальность ПО.

2Основание для разработки: содержит наименование документа на основании которого ведется разработка(план, приказ, договор). ГОСТ ВПО. 230100 - «ИиВТ»

3Назначение разработки — описание функционального и эксплуотационного назначения продукта с указанием категории пользователя.

4Требования к программе и програмному изделию.

4.1Требование к функциональным характеристикам — выполняемые функции, описан состав характеристики исходных данных и результатов, критерий эффективности.

4.2Требования к надежности — указывается уровень надежности системы, время восстановления после сбоя. Действия разрабатываемоего продукта по увеличению надежности результатов: контроль входной и выходной инф-ии, создание резервных копий и т.д.

4.3Условия эксплуатации — особые требования: когда система эксплуатируется в нестандартных условиях. Указывается вид обслуживания. Квалификация персонала. Требования не предъевляются

4.4Требования к составу и параметрам тех средств — тип микропроцессора, объем памяти, внешние устройста(мин, рекомендуемые).

4.5Требования к совместимости: исп ОС и программы. Защита обеспечивается встроенными системами ОС.

5Требования к программной документации — руководство программиста, пользователя, сис админа, РПЗ. На все документы существуют госты. РПЗ оформляется в соотвнтствии с ГОСТом 19.176108

6Технико-экономические показатели: указывать ориентировочную экономическу эффективность, годовую потребность и эк преимущества.

7Планируемая работа

8Перечень графического материала и литературы.

 


Дата добавления: 2019-02-12; просмотров: 472; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!