|
Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Нижнекамский химико-технологический институт (филиал)Стр 1 из 13Следующая ⇒
Нижнекамский химико-технологический институт (филиал) Государственного образовательного учреждения высшего профессионального образования «Казанский государственный технологический университет» Технологии программирования Текст лекций 2007 Федеральное агентство по образованию Нижнекамский химико-технологический институт (филиал) Государственного образовательного учреждения высшего профессионального образования «Казанский государственный технологический университет» Технологии программирования Текст лекций Нижнекамск 2007 Составители: О.В. Ибушева, А.Р. Нигматуллина, Н.Н. Саримов. Технологии программирования: Текст лекций / Нижнекамский рег. уч.-мет. центр; Сост.: О.В.Ибушева, А.Р.Нигматуллина, Н.Н.Саримов. Нижнекамск, 2007.
Пособие предназначено для обеспечения курса лекций по дисциплине «Технологии программирования» для студентов, обучающихся по специальности 230102 - Автоматизированные системы обработки информации и управления и по направлению подготовки бакалавров 230100 – Информатика и вычислительная техника.
Подготовлено на цикле информационных технологий при кафедре АТПП Нижнекамского химико-технологического института. Печатается по решению методической комиссии по циклу дисциплин автоматизации и электропривода.
Рецензенты: д. ф.-м. н., профессор КазГУ И.Б.Бадриев, к. ф.-м. н., доцент КазГУ О.А.Задворнов. введение Цели и задачи курса «Технология программирования» 1. Умение формулировать требования к программным средствам. 2. Оценивать качество и эффективность программного изделия. 3. Выбирать программные средства, наиболее соответствующие запросам пользователя. 4. Научиться современным методам и навыкам проектирования, тестирования, а также сопровождению программного обеспечения. Классификация программного обеспечения Программным обеспечением (ПО) вычислительной машины называется совокупность программ и сопровождающей их документации, позволяющих использовать вычислительную машину для решения задач. Различают системное (общее) и прикладное (специальное) ПО. · Системное ПО включает программы, необходимые для согласования работы всего вычислительного комплекса при решении задач, а также при разработке новых программ. По функциональному назначению в системном ПО выделяют: 1. Операционную систему – это комплекс управляющих программ, обеспечивающих функционирование вычислительной машины, включая планирование и управление ресурсами ЭВМ, решение задач по запросам пользователей, управление вводом-выводом данных. Операционные системы можно рассматривать как программное расширение аппаратурной части вычислительной машины. 2.
Под системой программирования понимают комплекс средств для разработки и отладки программ. В систему программирования входят языки программирования, трансляторы, различные обслуживающие программы для редактирования текстов и отладки программ. 3. Системные обслуживающие программы (утилиты) предназначены для выполнения типовых действий по подготовке носителей информации, обслуживанию файлов и т.д. В ряде случаев утилиты считают частью ОС. 4. Средства контроля и диагностики – служат для проверки исправности отдельных устройств и локализации выявленных неисправностей. · Прикладное ПО разрабатывается и используется для решения конкретных задач пользователей ЭВМ. Обеспечение целей создания программных изделий Тема 3. Внутреннее проектирование программных изделий Методы проектирования программ Прежде чем создавать программное изделие, необходимо четко уяснить суть задачи и ее структуру. Для этого задачу разбивают на уровни абстракций, как правило, методом декомпозиции. Тема 4. Структурированные программы Теорема о структурировании Теорема. Любая простая программа функционально эквивалентна программе, составленной из элементов базисного множества: последовательность, if then else, whilе do с использованием функций и предикатов исходной программы, а также присваиваний и тестов над дополнительным счетчиком. Доказательство (конструктивное). Рассмотрим произвольную простую программу с произвольным числом функциональных предикатных узлов, пронумерованных от 1 до n. Номер 1 соответствует входной линии программы. Выходной линии программы присвоим номер 0. Дадим выходным линиям каждого функционального и предикатного узла номер следующего функционального или предикатного узла. Если выходная линия соответствует выходной линии программы, то ей присвоим номер 0.
Пример. Пусть требуется построить помеченную структурированную программу для следующей программы. Элементарные программы gi для нее будут иметь вид:
Принцип простой индукции Пусть Согласно простой математической индукции для этого необходимо: 1) доказать, что справедливо высказывание 2) Доказать, что если для Рассмотрим пример использования простой индукции. Необходимо доказать, что для
1) Используя простую индукцию, необходимо доказать, что 2) Предположим, что справедливо высказывание
Покажем, что справедлива формула и для
Принцип обобщенной индукции Пусть 1. доказать, что справедливо 2. доказать, что если справедливо
Пример доказательства правильности программы методом индуктивных утверждений Пусть имеется следующая программа поиска максимального значения среди элементов хi,j.
1-8 – это точки, в которых предположительно имеют место следующие утверждения: · А1 : х – массив чисел, состоящий из m строк и n столбцов,
· А2 : · А3:
· А8 :
Доказательство. 1) Путь 1→2: 2) Путь 2→3: Дано утверждение А2. Требуется доказать А3. При первом вхождении в точку 3 3) Путь 3→4→5→3. Пусть справедливо утверждение А3. Покажем, что оно остается справедливым при переходе по данному пути. Пусть в точке 3 в какой-то момент времени 4) Путь 3→4→6→3. Доказательство аналогично пункту 3 за исключением того, что здесь нашлось 5) Путь 3→7→2. Пусть справедливо утверждение А3. Покажем, что при прохождении пути 3→7→2 будет справедливо утверждение А2. Из точки 3 в точку 2 мы попадаем, когда ложна проверка 6) Путь 2→8. Так как мы вышли из точки 2 в точку 8 проверка неравенства . . . . if <условие N> then <выражениеN> else <выражение N+1> В данном выражении последовательно проверяются условия. Если i-ое условие выдает истину, то функция F выдает значение выражения i. Если ни одно из условий не выдает истину, то функция выдает значение выражения N+1. Рекурсия вводится в этот язык следующим образом: функция F может входить как часть в любом из выражений или условий в программе. Такое появление F называется рекурсивным обращением к этой функции. Дополнительно для каждой такой рекурсивной программы необходимо указать область определения, т.е. указать для каких аргументов х1,…хn применима программа. Примеры рекурсивных программ 1. Рассмотрим программу, применимую F ( x) = if х=0 then 1 else х·F(х-1) Для иллюстрации работы данной программы выполним ее, например, для х=4:
2. Функция Аккермана. Эта функция применима А(х,у) = if х=0 then у+1 else if y=0 then A(x-1,1) else A(х -1, A(x, y-1)) Проследим, каким образом выполняется эта программа для х=1, у=2. А(1,2)=А(0, А(1,1))=А(0, А(0, А(1,0)))= =А(0, А(0, А(0,1)))=А(0, А(0,2))= А(0,3) =4 Из этого примера видно, что при вычислении рекурсивных функций могут возникать неоднозначности, связанные с последовательностью вычисления аргументов. Например, при обращении А(0, А(1,1)) мы предполагали, что А(1,1) должна быть вычислена прежде, чем будут продолжены вычисления, относящиеся к внешнему обращению к функции А. Если отдать предпочтение вычислениям, связанным с внешним обращением, то вычисления будут производиться в следующем порядке: А(1, 2) = А(0, А(1,1)) = А(1,1) + 1 = = А(0, А(1,0)) + 1= (А(1,0) +1) + 1 = = А(0,1) + 2 = 2 + 2 = 4 Можно доказать, что если к одним и тем же аргументам некоторой рекурсивной функции применять две разные последовательности ее вычисления, то результат будет одним и тем же при условии конечности этих последовательностей. Однако возможны случаи, когда последовательность не будет конечной. Рассмотрим следующий пример для демонстрации этого факта. Рассмотрим следующую функцию, применимую F ( x,у) = if х=0 then 0 else F(0, F(х,у)) Проследим за вычислением F, используя два различных правила вычисления: 1) при предпочтении внешнему обращению F (1,1) = F(0, F(1,1))=0; 2) при предпочтении внутреннему обращению. F (1,1) = F(0, F(1,1))= F(0, F(0,F(1,1)))=… Таким образом, в первом случае последовательность конечна и функция А=0, во втором случае вычисления не заканчиваются. Для того чтобы устранить неопределенность, необходимо задать правила вычисления. Большинство языков программирования при обращении к функции (процедуре) предварительно вычисляют аргументы, отдавая тем самым предпочтение внутреннему вызову. Списки и операции над ними Большинство рекурсивных алгоритмов связано с работой со списками в силу рекурсивного определения самих структур данных - списков. Для описания этих алгоритмов введем следующую нотацию. Список – это набор объектов, отделенных друг от друга пробелами и заключенных в квадратные скобки []. Объектами, входящими в такие списки, являются атомы (неделимые элементы) или другие списки. Атом – это строка буквенно-цифровых символов, не содержащая пробелы. Для того чтобы отличать атомы от переменных, будем считать, что переменные записываются строчными буквами, а атомы – прописными. Например, [А В С] – список из трех элементов, каждый из которых является атомом. [А [В А [С]]D] – список, в котором на верхнем уровне три элемента: второй элемент сам является списком из трех элементов, в котором третий элемент – это список из одного элемента С. Для пустого списка, т.е. списка, не содержащего одного элемента, выделяется специальное имя nil. Наиболее распространенными операциями над списками и атомами являются следующие. 1. Проверка на равенство: [А В] = [А В] выдает true , [А В] = [В А] и во всех других случаях - false. 2. Проверка аtom(х) - применима к любым объектам: атомам или спискам. Выдает true, если х является атомом или пустым списком. 3. Саr(l) применима к любому непустому списку. В качестве результата выдается первый на верхнем уровне элемент этого списка: Саr([А В С])=А; Саr([[А В]С D])=[А В]; Саr(nil) и Саr (А) – не определены. 4. Cdr( l) – применима к любому непустому списку l; результатом является список, полученный из списка l путем исключения первого элемента: Cdr([А В С]) = [В С]. 5. Соns(х,l) - объединяет элемент х со списком l: Соns(А, [D E]) = [А D Е]; Соns([А В], [D E]) = [[А В] D E]. Примеры программ работы со списками 1. Программа, определяющая является ли х элементом списка l на верхнем уровне. member (x,l) = if l=nil then false else if x=car (l) then true else member (x,cdr (l)) 2. Программа, присоединяющая список l2 в конец списка l1. append (l1, l2) = if l1 = nil then l2 else cons (car (l1), append (cdr (l1), l2)) 6.3. Примеры доказательства правильности рекурсивных программ Для доказательства правильности рекурсивных программ может быть использован метод обобщенной индукции. Пример 1. Докажем, что функция Аккермана (см. 6.1) конечна. В качестве множества х выберем множество пар натуральных чисел, упорядоченных в лексикографическом порядке, т.е. (х,у) < ( Для доказательства конечности функции Аккермана необходимо доказать: 1. А(0,0) – конечна. Действительно, А(0,0) = 1 - конечна. 2. Доказать, что если А(х,y) конечна Докажем это. Для этого предположим, что Тогда получим: а) если б) если в) если Пример 2. Рассмотрим рекурсивную программу, вычисляющую пересечение двух упорядоченных списков l1 и l2. Intord (l1,l2) = if l1=nil then nil else if l2=nil then nil else if car(l1) < car(l2) then intord(cdr (l1),l2) else if car (l2) < car (l1) then intord(l1, cdr(l2)) else cons (car(l1), intord (cdr(l1), cdr(l2))) Доказательство правильности будем проводить по парам возможных длин списков. Пусть d1 = length (l1), d2 = length (l2). Для доказательства правильности покажем, что: 1. функция работает правильно для наименьшей пары длин, т.е. для ( d1, d2)=(0,0). Очевидно, что списки с длинами (0,0) – есть пустые списки, поэтому intord (nil,nil) = nil . 2. покажем, что если Возможны следующие варианты. а) l1 =nil или l2 =nil. Здесь intord( l1, l2)= nil – функция работает правильно. б) car(l1)<car(l2). Здесь intord( l1, l2)= intord( cdr( l1), l2)), но в) car ( l2) < car ( l1), доказывается аналогично варианту б). г) car(l1)=car(l2). Здесь Тема 7. Отладка программ Задачи отладки программ Под отладкой понимается процесс, позволяющий получить программу, функционирующую с требующимися характеристиками в заданной области входных данных. В результате отладки программа должна соответствовать определенной фиксированной совокупности правил и показателей качества, принимаемой за эталонную для данной программы. Процесс отладки программ включает: создание совокупности тестовых эталонных значений и правил, которым должна соответствовать программа по выполняемым функциям, структуре, правилам описания, значениям исходных и соответствующих им результирующих данных; статическую проверку текстов разработанных программ и данных на выполнение всех заданных правил построения без исполнения объектного кода; тестирование программы с ее исполнением в объектном коде и с разными уровнями детализации: детерминированное, стохастическое и тестирование в реальном времени; диагностику и локализацию причин отклонения результатов тестирования от заданных эталонных значений или правил; изменение программы с целью исключения причин отклонения результатов от эталонных. Основным методом обнаружения ошибок при отладке программ является их тестирование. В технической диагностике тест - это последовательность наборов сигналов (исходных данных), которые подаются на вход изделия, и соответствующие им наборы эталонных правильных сигналов (результирующих данных), которые должны быть получены на выходе. Для каждого тестового набора указываются координаты (точки) ввода исходных данных и координаты (точки) контроля результатов. Кроме того, при тестировании необходимо задавать допуски на отклонение результирующих данных от эталонных, в пределах которых следует, что полученные результаты соответствуют эталонным. Степень отклонения получаемых результатов от эталонов используется для оценки качества изделий и соответствия их техническим требованиям. Программы, как объекты тестирования, имеют ряд особенностей, которые отличают процесс тестирования от традиционного, применяемого для проверки аппаратуры и других технических изделий. Для сложных КП практически всегда отсутствует полностью определенный и точный эталон для всех тестовых наборов. В связи с этим для тестирования в качестве эталонов используется ряд косвенных данных, которые не полностью отражают функции и характеристики отлаживаемых программ. Для сложных программ недостижимо исчерпывающее их тестирование, гарантирующее абсолютно полную их проверку. Поэтому тестирование проводится в объемах, минимально необходимых для проверки программ в некоторых ограниченных пределах изменения параметров и условий функционирования. Ограниченность ресурсов тестирования привела к необходимости упорядочения применяемых методов и конкретных значений параметров с целью получения при тестировании наибольшей глубины проверок программ. В ряде случаев процесс исполнения программ и получаемые результаты зависят от непредсказуемого изменения входных и промежуточных данных, а также от реального времени. Вследствие этого невозможно создать единственный универсальный метод тестирования и приходится применять ряд значительно различающихся категорий тестов. Каждая категория тестов отличается целевыми задачами, проверяемыми компонентами программы и методами оценки результатов. Только совместное и систематическое применение различных методов тестирования позволяет достигать высокого качества функционирования сложных КП. Целесообразно выделить три стадии тестирования: для обнаружения ошибок в программе; для диагностики и локализации причин обнаруженных искажений результатов; для контроля выполненных корректировок программ и данных. Основная цель тестирования для обнаружения ошибок выявление всех отклонений результатов функционирования реальной программы от заданных эталонных значений. Задача состоит в обнаружении максимального числа ошибок, в качестве которых принимается любое отклонение от эталонов. Чем больше ошибок выявляется на этой стадии при каждой операции тестирования, тем выше эффективность тестов и обоснованность затрат на их выполнение. С этих позиций тесты, не способствующие обнаружению ошибок и только подтверждающие корректность функционирования программ, являются неэффективными, так как приводят к бесполезным затратам. После тестирования для обнаружения ошибок применяется тестирование для их диагностики и локализации. Основная задача - точно установить место искажения программы или данных, явившегося причиной отклонения результатов от эталонных. Затраты оправданы, и тестирование выполнено успешно, если оно приводит к полной локализации первичных ошибок, подлежащих исправлению. После локализации и устранения обнаруженных ошибок применяется контрольное тестирование, задача которого состоит в подтверждении правильности выполненной корректировки программы. В этом случае успешность тестирования определяется отсутствием проявления ранее обнаруженной, локализованной и устраненной ошибки, а также отсутствием вторичных ошибок, которые могут появиться при корректировке. Методы разработки тестов Предположения об ошибках Заметим, что некоторые программисты обладают умением выискивать ошибки и без привлечения какой-либо методики тестирования. Объясняется это тем, что человек, обладающий большим практическим опытом, часто подсознательно применяет метод проектирования тестов, называемый предположением об ошибках. При наличии определенной программы, зная спецификации этой программы, он интуитивно предполагает вероятные типы ошибок и разрабатывает тесты для их обнаружения. Нижнекамский химико-технологический институт (филиал) Государственного образовательного учреждения высшего профессионального образования «Казанский государственный технологический университет» |
Последнее изменение этой страницы: 2019-05-08; Просмотров: 281; Нарушение авторского права страницы