Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Надежность и диагностика компонентов инфокоммуникационных и информационно-управляющих систем.-1

.pdf
Скачиваний:
0
Добавлен:
20.11.2023
Размер:
3.78 Mб
Скачать

{***************************************************************} {спецификация имитационной модели смешанной СТИ функция: имитация передачи отсчетов по каналу связи для определения вероятностных и статистических характеристик

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

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

среднеквадратическое отклонение приведенной погрешности

входные параметры: номер отсчета

integer 255=

 

2^m–1>=1

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

real [0;1]

кратность обнаруживаемых ошибок

integer

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

integer

выходные параметры: вероятность правильной передачи

real [0;1]

вероятность обнаружения

real [0;1]

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

real [0;1]

вероятность трансформации

real [0;1]

математическое ожидание

real

дисперсия

real

среднеквадратическое отклонение

 

приведенной погрешности

real

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

внешние эффекты: нет } {***************************************************************}

221

Проектирование логики модуля

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

1. Выберите язык. Выбор языка обычно диктуется требованиями контракта или принятыми в организации стандартами. Хотя выбор языка и включен сюда, на самом деле язык должен быть выбран в начальный период работы над проектом, поскольку он влияет на планирование работы над проектом (например, обучение программистов, подготовка компиляторов и средств тестирования).

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

3.Проверьте правильность внешних спецификаций. Правиль-

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

4.Выберите алгоритм и структуры данных. Жизненно важ-

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

222

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

5.Напишите первое и последнее предложения. Следующий шаг – написать предложения PROCEDURE и END будущего модуля (или их эквиваленты, в зависимости от избранного языка программирования). Отметим, что мы здесь опустили традиционный этап вычерчивания блок-схем; причины этого будут рассмотрены ниже.

6.Объявите все данные из сопряжения. Следующий шаг со-

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

7.Объявите остальные данные. Напишите предложения, ко-

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

8.Детализируйте текст программы. Следующий шаг – итера-

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

9.Отшлифуйте текст программы. Теперь модуль нужно от-

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

223

10. Проверьте правильность программы. Вручную проверяет-

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

впоследнем разделе этой главы.

11.Компилируйте модуль. Последний шаг – компиляция модуля. Этот шаг отмечает переход от проектирования к тестированию; компиляцией, по существу, начинается тестирование программного обеспечения.

Пошаговая детализация

Структурное программирование до сих пор было у нас представлено как свойство или оценка окончательного текста программы. Необходимо добавить еще один ключевой элемент: методологию, или особенности мыслительного процесса, управляющего проектированием модуля для получения структурной программы. Этот мыслительный процесс, который мы будем сейчас рассматривать, называется пошаговой детализацией [1].

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

Для иллюстрации этого процесса применим его для разработки фрагмента программы имитирующую передачу отсчетов по каналу связи для определения вероятностных и статистических характеристик. Исходная формулировка такова:

(обнуление счетчиков)

While (не достигли максимального числа переданных сообщений) do

Begin

224

If (вес вектора ошибки меньше кратности исправляемой

ошибки)

Then (передача отсчета произошла без искажения, увеличиваем на единицу счетчик правильных передач);

If (вес вектора ошибки больше кратности исправляемой

ошибки)

Then (при передаче сообщения произошла ошибка, и поскольку она не была исправлена при декодировании на приемной стороне, увеличиваем на единицу счетчик трансформаций);

Увеличиваем счетчик переданных сообщений: End;

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

(обнуление счетчиков) While N<100000 do Begin

If (e<=s)

Then (передача отсчета произошла без искажения, увеличиваем на единицу счетчик правильных передач);

If (e>s)

Then (при передаче сообщения произошла ошибка, поэтому она была исправлена при декодировании на приемной стороне, увеличиваем на единицу счетчики правильных передач и исправленных ошибок);

N=N+1;

End;

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

225

(обнуление счетчиков) While N<100000 do Begin

If (e<=s)

Then Cpr=Cpr+1; If (e>s)

Then Ctrns=CTrns+1; N=N+1;

End;

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

N:=0;

Cpr:=0;

Ctrns:=0;

D:=0;

While N<100000 do

Begin

If (e<=s)

Then Cpr=Cpr+1;

If (e>s)

Then Ctrns=Ctrns+1;

N=N+1;

End;

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

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

226

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

3.2.8. Стиль программирования

Центральное понятие, связанное со структурным программированием – стиль программирования, т.е. манера, в которой программист (правильно или неправильно) употребляет особенности своего языка программирования – в том же смысле, как писатель (правильно или неправильно) использует естественный язык. Именно плюсы и минусы стиля программирования обычно оказываются основной причиной таких, например, суждений: «Я видел программу, очень красиво размещенную на странице и без единого GO TO, но при этом абсолютно непостижимую, и другую, совершенно понятную программу, в которой было несколько GO TO».

Ясность программирования

Задача программиста должна состоять в том, чтобы писать на исходном языке программы, предназначенные для аудитории, состоящей в первую очередь из людей, а не машин. Эта задача требует уделить больше внимания ясности, простоте и доступности текста за счет игнорирования менее важных критериев, например краткости (число ударов по клавишам, необходимых для того, чтобы напечатать программу) или машинной эффективности. Выполнение следующих правил помогает писать ясные программы [1].

Используйте осмысленные имена. Это правило выражает са-

мый важный принцип стиля программирования. Ничего нет хуже программы с именами XX, XXX, ХХХХ, XY, ЕКК, ЕККК, А и AI, заполненной комментариями, разъясняющими смысл и назначение этих имен. Простой прием – использование более длинных содержа-

227

тельных имен – значительно облегчает чтение программы и сводит к минимуму количество необходимых комментариев. Как правило, имена переменных должны содержать от 4 до 12 символов. Слишком длинные имена, типа ЧИСЛО _ ТРАНФОРМАЦИЙ _ НА _ СООБЩЕНИЕ, нежелательны, потому что они отвлекают внимание от собственно программы и сами подвержены ошибкам.

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

иVALUES, или ряд переменных с именами BRACA, BRACB, BRACC

иBRACD. Это усложняет чтение программы. Выбирая осмысленные имена, старайтесь, чтобы они были как можно менее похожи.

Если в идентификаторах используются цифры, помещайте их только в конце. Цифры 0, 1, 2 и 5 легко спутать с буквами О, I, Z и S. Если уж цифры в именах переменных необходимы, помещайте их в конце.

Никогда не используйте в качестве идентификаторов ключевые слова.

Вследующем примере на языке Cи++

int max(int x, int y)

{

if (x > y) return x;

else

return y;

}

max, x и y – имена или идентификаторы. Слова int, if, return и else – ключевые слова, они не могут быть именами переменных или функций и используются для других целей.

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

228

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

Во избежание неоднозначности употребляйте скобки. Поря-

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

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

Рассмотрим пример на С++:

int simple_function(const int&, int); int simple_function(const int& a, int b);

{

a = 1;//Компилятор выдаст ошибку! Нельзя изменять перемен-

ную a

return 0;

}

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

a = b = c = d;

(присвоение нескольким переменным одного и того же значе-

ния).

x = 2 * (a = 3 + b);

(выполнение присваивания в арифметическом выражении).

229

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

a = 3 + b x = 2 * а;

Нe изменяйте значение параметра цикла в теле цикла. Изме-

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

Использование языка

Вторая важная характеристика стиля программирования – способ, которым программист отбирает для употребления (или отбраковывает) возможности языка программирования. Общее правило здесь состоит в том, чтобы понять и использовать все возможности языка, но остерегаться плохо продуманных его особенностей и зависящих от реализации трюков [1].

Изучите и активно используйте возможности языка. Иног-

да можно увидеть программу на Delphi, содержащую цикл FOR i:=1 to n DO для обнуления всех элементов массива. Обычно это является признаком слабого знания языка, поскольку достаточно было бы одного оператора Length(mas,0).

Изучите и используйте библиотечные и встроенные функции.

Многие программисты знакомы с математическими функциями, реализованными в языке (квадратный корень, синус, косинус, абсолютная величина), но меньше знают о других полезных функциях. Чтобы дать некоторое представление о ряде полезных возможностей языка, заметим, что Delphi содержит огромное количество встроенных функций, среди них традиционные МАХ и MIN (выдает максимальное/минимальное число из двух целых значений), функции над одним массивом, такие как SUM (находит сумму элементов массива, состоящего из чисел с плавающей точкой). Функции по работе со строками такие, как сoncat (соединяет несколько строк в одну), сopy

230