
- •Лекции по
- •(Те что я нашел)
- •Информация и данные.
- •Анализ программ, не содержащих ветвлений
- •Если p{ а }q и q{ b }r, то выполняется p{ a;b }r.
- •Проектирование цикла с помощью инварианта Задача 1. Найти сумму величин 1/iот 1 до тех пор, пока она не станет больше некоторого наперед заданного числаa.
- •Будем искать решение нашей задачи в виде цикла, имеющего следующий вид:
- •Линейные структуры данных.
- •Операции над линейной структурой данных
- •Виды линейных структур данных.
- •4)Стек на базе массива
- •Тема: Анализ создаваемых абстракций
- •Полнота
- •Аназиз типов данных
- •Операции egual, similar и copy
- •Функция абстракции
- •Функция абстракции есть
Операции egual, similar и copy
Может показаться, что абстракции данных должны предоставлять операции copy и equal автоматически, т. е. что каждый тип автоматически должен быть обеспечен этими операциями и что их реализации должны быть сгенерированы компилятором. Однако автоматически такие реализации сгенерированы быть не могут, так как они зависят от интерпретации представления, т. е. от функции абстракции.
Проверка на равенство не может быть реализована автоматически потому, что два абстрактных объекта могут быть равны, даже если их представления различны. Возьмем в качестве примера рассмотренную нами ранее реализацию рациональных чисел, в которой представления задаются не в сокращенной форме. Очевидно, что рациональное число, представленное записью
{num: I, denom: 21}
равно рациональному числу, представленному записью {num: 13, denom: 26}.
Копирование не может быть реализовано автоматически потому, что не всегда ясно, из чего состоит объект. Например, при копировании упорядоченного списка нужно ли нам копировать только верхний узел, чтобы копия разделяла правое и левое поддеревья с оригиналом, или мы должны копировать также и правое и левое поддеревья? Правильный ответ зависит от значения типа.
Несмотря на то что реализация таких операций, как equal, осуществляется программистом, чтобы гарантировать одинаковые значения операций с такими именами, мы рекомендуем придерживаться принятых соглашений. Мы приняли соглашение, согласно которому имя equal резервируется для условия равенства, т. е. когда невозможно различить два равных объекта. Следовательно, два изменяемых объекта равны тогда и только тогда, когда они являются одним и тем же объектом; в противном случае мы могли бы различить их, применив к одному из них модифицирующую операцию. Например, рассмотрим две ситуации, показанные на рис. 4.18. Здесь х = у, но х ~ = z.
Мы используем имя similar для операции, которая имеет дело со взаимосвязью и , а именно с фактом совпадения значений двух объектов. Мы требуем, чтобы результат операции copy совпадал по значению со своим аргументом, но не разделял с этим аргументом никаких компонентов. Так, объект z мог быть получен при вызове copy (х).
В отношении имен equal, copy и similar встроенные в язык CLU типы отвечают этим соглашениям. Должны отвечать им и определяемые пользователями типы. Таким образом, если тип данных intset предоставляет эти операции, их спецификации должны быть такими, как показано на рис. 4.19, а их реализации— как на рис. 4.20. Отметим, что операция similar сравнивает значения двух своих аргументов и проверяет, содержат ли они одни и те же элементы. Операции equal и copy могут быть реализованы в терминах операций equal и copy для массивов.
Множество целых на базе списка Вселенная объектов
Y
Rep
2
5 5
Z
13 13
Область
абстрактных данных
{5,
13}
Рис. Две концепции равенства.
equal = proc (si, s2: intset) returns (bool)
effects Возвращает значение true, если si и s2— один и тот же объект intset.
similar = ргос (si, s2: intset) returns (bool)
effects Возвращает значение true, если si и s2 содержат одинаковые элементы.
copy = proc (s: intset) returns (intset)
effects Возвращает новый объект intset, содержащий те же элементы, что и s
Рис. Спецификации операций equal, copy и similar для наборов целых чисел intset.
equal = proc (si, s2: cvt) returns (bool)
return (si = s2) % используется rep$equal
end equal
similar = proc (si, s2: Intset) returns (bool)
return (subset (si, s2) cand subset (s2, si))
end similar
% subset — это внутренняя программа, которая возвращает значение true, если % si принадлежит s2. subset = proc (si, s2: cvt) returns (bool) i; int := rep$low (si) while i (== rep$high (si) do
if member (up (s2), s1 [i]) then return (false) end
i := i+ I
end
end subset
copy = proc (s: cvt) returns (cvt)
return (rep$copy (s))
end copy
Рис. Реализации операций equal, similar и copy для наборов целых чисел intset.
Абстракция.Виды и методы абстракции в программировании. Понятие про абстрактные типы данных (А.Т.Д.).Процедурная абстракция и абстракция данных.
Абстракция– это отвлечение от несущественных сторон изучаемого явления с целью
1)лучше понять какую-то одну сторону изучаемого явления, 2)это инструмент познавательной деятельности, приводящий к абстрактным понятиям. Задача абстрагирования и последующей декомпозиции типична для процесса создания программы: - декомпозиция используется для разбиения программы на компоненты, кот-е могут быть затем объеденены, позволив решить основную задачу, абстрагирование же предполагает продуманный выбор компонент.
Мы последовательно выполняем то один, то другой из этих процессов до тех пор, пока не сведём исходную задачу к набору подзадач, решение которого известно. ЯП должен содержать средства для создания своих собственных абстракций. Наиболее распространённым механизмом такого рода явл. понятие процедур. Разделяя в прогр. тело процедуры и обращения к ней ЯВУ(языки высш. уровня) реализуют тем самым два важных метода абстракции: 1)абстракция через параметризацию, 2)абстр. через спецификацию. Абстр. через параметризацию позволяет нам, используя параметры, представить неограниченный набор различных вычислений одной программой, кот-я есть абстракция всех этих методов. Абстр. через П. явл. важным средством повышения универсальности программ.
Абстр. через спецификацию позволяет нам абстрагироваться от процесса вычислений, описанных в теле процедуры до уровня знания лишь того, что данные процедуры должны в итоге реализовать. Это достигается путём задания для каждой процедуры спецификации, описывающей эффект её работы, после чего смысл обращения к данной процедуре становится ясным через анализ этой спецификации, а не самого тела процедуры. Мы пользуемся А. через С. всякий раз, когда связываем с процедурой некий комментарий, достаточно информативный для того, чтобы иметь возможность работать с ней без анализа тела процедуры. Одним из способов написания таких комментариев – это использование пар утверждений: requires(начальные условия),effects(конечные условия). Для уяснения смысла обращения к процедуре придерживаемся двух чётких правил: 1)после выполнения процедуры можно считать, что конечное условие выполнено, 2)можно ограничиться только теми свойствами, которые подразумевают конечные условия.
Виды абстракций: А. через параметризацию и А. через специф. явл. мощными средствами создания программ. Они позволяют определить три различных вида абстракций: 1)процедурная А., 2)А. данных, 3)А. через итерацию. Все они используют оба метода абстракции. Процедурная А. позволяет расширить заданную некоторым языком виртуальную машину новой операцией. А. данных (или тип данных) состоит из набора объектов и набора операций, характеризующих поведение этих объектов. А. через итерацию даёт возможность не рассматривать информацию, не имеющую прямого отношения к управляющему потоку или циклу. АТД является уровнем средств определения типа данных с использованием абстрактных типов. Появился в языках 3-го поколения. Это, по существу, определение некоторого понятия в виде класса (одного или более) объектов с некоторыми свойствами и операциями. АТД часто отождествляется с соотв. мн-вом операций. В определение АТД входят след. 4 части: 1)внешность – имя определяемого типа с указанием типов, их аргументов и значений и т.д., 2)абстрактное описание операций и объектов средствами языка спецификаций, 3)конкретное описание операций и объектов средствами обычного ЯП, уровень кот-го не выше уровня языка второго поколения, 4)описание связи между 2) и 3), объясняющее в каком смысле часть 3) корректно представляет часть 2).
В большинстве ЯП 3-го поколения есть только 1) и 3). Представление должно быть защищено от внешнего воздействия. Классификация типов АТД: 1)тип наз. инкапсулированным, если предусматривается защита, 2)тип наз. абстрактным, если предусм. абстрактное описание, 3)тип наз. пакетированным, если предусмотрено только ср-во объединения объектов и операций в одно целое (модули языка Паскаль). Процедурная А. выполняет преобразование вх. аргументов в вых. с возможной модификацией вх. арг. При создании процедурных А. процедуры необх. минимизировать, т.е. в них должны быть реализованы только необх. действия. 1)св-во минимальности, 2)св-во обобщаемости – достигается использованием параметров вместо переменных, 3)простота – процедура должна обладать хорошо определённым и легко объяснимым назначением, независимым от контекста её использования. Абстракция данных. Процедуры дают нам возможность добавлять в базовый уровень языка новые операции, а А. данных – новые типы. <А. данных>=<объекты, операции>. При этом мы требуем, чтобы пользователь употреблял эти операции непосредственно, не обращаясь к представлению. А. данных позволяет отложить окончательный выбор структур д. до момента, когда эти ст-ры д. станут нам вполне ясны. А. данных полезна при модификации и эксплуатации программ. Реализация А. данных. Каждая реализация имеет два типа – абстрактный тип и тип представл. Полнота. Тип явл. полным, если он обеспечивает достаточно операций для того, чтобы все требующиеся пользователю работы с объектами могли быть проделаны с приемлемой эффективностью.
Спецификации(С.). Виды спецификаций. Спецификация процедур. Спецификация А.Т.Д.
Этапы создания ПО:1.Изучение, 2.Проектирование, 3.Кодирование, 4.Тестирование и отладка, 5.Использование, 6.Повторное использование. На этапе проектирования что-то необходимо писать. В результате получаем спецификации. Спецификации проверяются на полноту и непротиворечивость. На этапе кодирования проверяется соответствие программы спецификации. Виды спецификаций:1)С. ЯП, 2)С. модулей, 3)С. процедур, 4)С. данных. Отличие процедуры от математ. ф-ции: 1)прцедуры могут иметь побочный эффект, 2)генерировать исключения, 3)могут обладать собственными данными, 4)может зацикливаться, т.к. обл. определения часто определяется PostFactum, 5)выдача неопределённого значения, 6)модификация глобальных объектов. Значением спецификации явл-ся набор всех программных модулей, ей удовлетворяющих. Этот набор модулей называется необходимым набором спецификаторов для данной спецификации. Критерии, применяемые к С. – ограниченность (С. д.б. настолько ограниченны, чтобы можно было отличить правильную реализацию от неправильной) и обобщенность. Два стиля написания С.: дефинитивный (описываются св-ва вх. и вых. значений, но нет алг-ма получения вых. значений) и операционный (приводится способ конструирования вых. значений). Свойства С.: 1)простота, 2)понимаемость. Факторы, обеспечивающие эти св-ва: 1)краткость, 2)избыточность, 3)структурированность. Третье св-во С. – полнота. Важность С. на различных этапах жизни прогр. обеспечения: Для разработчика спецификации дают сведения о том, что ему надо сделать, не ограничивая его в том, как это надо сделать. Пользователю они говорят, на что он может положиться при создании своих модулей. При тестировании они помогают генерировать тестовые данные.
При отладке помогают выявить ошибки и при их исправлении помогают избежать новых ошибок. В процессе сопровождения они могут использоваться, как часть документации, позволяя различать вопросы что? и как? (что это такое и как оно реализовано).
Мы будем определять абстракции посредством С., которая создаётся на базе языка С., кот. может быть как формальным, так и неформальным. С. отлична от любой, определяемой ей реализации абстракции. Все реализации сходны между собой, поскольку они реализуют одну и ту же абстракцию. Отличие их закл. в том, что это делается различными способами. Спецификация определяет их (реализаций) схожесть. С. – это ширма, отделяющая предмет, но позволяющая правильно судить о нём и пользоваться им. Спецификации процедур.
pname = proc(..)returns(..)
requires % этот оператор задаёт все необх. требования, modifies % идентифицирует все модифицируемые вх. данные, effects % описывает выполняемые функции. Обязательным явл. только effects.
Пр. coneat = proc(a,b:string)
returns (ab:string)
effects при возврате ab есть новая строка, содержащая символы из а (в том порядке, в кот-м они расположены в а), за кот-ми следуют символы из b (в том порядке, в кот-м они расположены в b).
C. обычно принципиально отличаются от программ, поскольку они фокусируют своё внимание на описании самой абстракции, а не её реализации.
Спецификация АТД.
Абстракция данных - необходимо понимать программы в терминах того, что АТД представляют, не заботясь о том, как они это делают, и независимо от этого понять, как они представляют абстрактные объекты, не заботясь о том, почему они были созданы. Спецификации для абстракции данных – значение типа не должно задаваться никакой его реализацией. Вместо этого должна иметься определяющая его спецификация.
dname=data tupe is
% список операций.
Описание % здесь приводится описание абстр. д.
Операции % задаются спецификации для всех операций
end dname
C. бывают: 1)алгебраическими, 2)логическими, 3)модельными. Алгебраич. С. состоят из двух частей: 1)синтаксическая, 2)аксиоматическая.
1)перечисляет область определения и области действия операций, применяемых в построении и использовании объектов выбранного типа д. 2)перечисляет аксиомы, описывающие желаемые свойства этих операций и отношения, которым эти операции удовлетворяют. Довольно легко писать такие аксиомы, но трудно их сделать непротиворечивыми и полными.
Логические С. Определяют некоторую операцию с помощью формул полной корректности: {P} A {Q}. P – предусловие, Q –постусловие. Каждая такая ф-ла включает в себя два предиката –предусл-е и постусл-е , а также сегмент пр-мы. Эта ф-ла означает: если св-во Р изначально верно и если выполняется А, то св-во Q становится верным после этого выполнения.
Модельными наз. С., описывающие новый объект в терминах других объектов, таких, кот-е по предположению понятны тем, для кого эта С. предназначена. Ср-ва моделирования: 1)таблицы (используются для описания конечных ф-ций, конечных отношений и табличных стр-р данных), 2)Равенства и системы подстановок, 3)логические ср-ва, 4)Графы, сети, диаграммы.
Логические спецификации. Понятие инварианта цикла. Проектирование цикла при помощи инварианта. Доказательство конечности цикла.
Верификация программы предполагает анализ её текста. Это отличает верификацию от тестирования, при котором происходит наблюдение за ходом ваполнения программы (ищем ошибки). В процессе верификации мы анализируем текст программы и делаем выводы по поводу всевозможных наборов вычислений, кот-е можно производить этой программой.
Логические С. Определяют некоторую операцию с помощью формул полной корректности: {P} A {Q}. P – предусловие, Q –постусловие. Каждая такая ф-ла включает в себя два предиката –предусл-е и постусл-е , а также сегмент пр-мы. Эта ф-ла означает: если св-во Р изначально верно и если выполняется А, то св-во Q становится верным после этого выполнения. Имеют большое значение для верификации программ. Аксиомы: 1)для операторов присваивания – для того, чтобы Р было верным после выполнения x:=E (где Е - выражение), достаточно, чтобы P[E->x] (т.е. св-во Р после замены всех вхождений х на Е было верным предельно).{P[E->x]}x:=E{P}. 2)Аксиома для последовательного выполнения: если {P}A{Q} и {Q}B{R} то {P}A; B{R}.
3)Аксиома для альтернативы: если {P и C}A{Q} и {P и не C}В{Q} то {P} если С то А иначе В{Q}. 4)Аксиома для цикла: true ПОКА а)ПОКА С ПОВТОРЯТЬ А{не С}, б)если {P и C}A{P} то ПОКА С ПОВТОРЯТЬ А{P}. Если Р инвариантно по отношению к действию А, т.е. если выполнение А оставляет {P} истинным при исходно верном {P}, во всяком случае когда С верно, то {P} тоже инвариантно по отношению к циклу. {P} наз. инвариантом цикла. Играет огромную роль при проектировании циклов, а значит и при построении программы систематическими методами. Цикл ПОКА определён: a)условием окончания {C}, б)инвариантом цикла {P}, в)действием А. Инвариант часто предстаёт в форме «такая-то переменная имеет в качестве значения такую-то величину». Следоват., позволяет накладывать постоянное условие на многократно выполняющиеся действия. Кроме этого для цикла (если он не бесконечен), надо доказать, что он закончится за конечное число шагов. Для этого надо для каждого цикла выделить некоторую связанную с циклом целую неотрицат. величину m, зависящую от переменных программы и называемую управляющей величиной (или функцией декремента) и показать, что каждое выполнение цикла уменьшает её, по крайней мере, на единицу.
Проектирование циклов при помощи инварианта. Например, имеется утверждение x>0 y=0 {while (y=x) do y:=y+1 } y=x, x,y – целые.
Доказать это утверждение старыми методами невозможно, нужны новые методы. Предположим следующее: 1)Предусловие гарантирует выполнение условия y<=x. 2)Выполнение тела цикла увеличивает y. 3)Так как между x и y конечное число значений, то наступит такой момент, что y=x. 4)Программа закончится, как только x=y.
Такой метод рассуждения аналогичен методу математической индукции в математике. В этом случае возможен выбор гипотезы индукции. Для программы гипотеза индукции называется инвариантом цикла. Инвариант должен удовлетворять условиям: 1)Инвариант истинен перед первым выполнением цикла. 2)Вычисление предиката В не нарушает инвариант. 3)Выполнение тела цикла не меняет инвариант. 4)Нарушение условия В и условие инварианта – из них должно следовать выполнение условия Q. 5)Цикл завершается за конечное число шагов.
Схема проектирования цикла при помощи инварианта. Основная идея – выражение взаимосвязи между меняющимися в теле цикла объектами в виде неизменного условия – инварианта, кот-е выполнено для начальных, промежуточных и конечных состояний объектов. Польза инварианта состоит в том, что такое статическое описание связей между изменяющимися объектами легко понимаемо и позволяет, зная, как меняются одни объекты, выводить, как должны изменяться другие.
Проектирование цикла: Дано P{while B do S}Q. 1)Продумать стратегию решения зедачи. Найти Inv, 2)найти В, 3)найти начальное значение параметров цикла из условия истинности инварианта, 4)найти S, 5)найти ф-лу для m и доказать, что при выполнении тела цикла m уменьшается по крайней мере на 1.
Рекурсия. Рекурсия и рекурсивные определения. Рекурсия в программировании. Св-ва рекурсивных алгоритмов. Этапы рекурсивного анализа. Рекурсия и итерация.
Обычно всякое новое понятие опр-ся через другие понятия, кот. предполагаются уже известными. (напр tg(x)=sin(x)/cos(x)).
Двигаясь от определяемых понятий к используемым мы в конце концов приходим к первичным (не определяемым в данной теории) понятиям (пр. точка, прямая, число и т.д.). Похожая ситуация и в программировании. Каждую программу можно представить в виде набора определений. Каждое такое определение использует набор команд, базовых определений. Так составляя определения мы в конце концов приходим к конечной программе. Но и в математике и в программ-ии встречаются «опр-я», не укладывающиеся в эту схему.
Пр.: n! = {1, если n=0; n*((n-1)!), если =n>0} На первый взгляд это определении кажется бессмысленным, но оно работает! 0!=1, 1!=1, 2!=2,… Это определение отличается от бесполезных, хотя и верных определений
(1) fact(n)=fact(n+1)/((n+1)(n+2)) или (2) fact(n)=fact(n)
Отличия: равенство это не определение, а требование к функциям. Второе – ему удовлетв. любая функция. Первое более сильное, но ему удовл. ф-я вида fact1(n)=c*fact(n) при любом натур. с.
И, наконец, требованию удовл лишь одна ф-я.
Предп. что их две. Пусть это f1 и f2. Это значит, что : f1(0) = f2(0) = 1; f1(n) = n*f1(n-1); f2(n) = n*f2(n-1). Докажем, что f1(k)=f2(k). при любом нат. к. Рассуждаем по индукции:
1) Базис индукции f1(0)=f2(0)=0
2) Шаг индукции. Предп., что f1(k-1)= f2(k-1) Докажем, что f1(k)=f2(k) Действительно f1(k)=k*f1(k-1)=k*f2(k-1)= f2(k), доказанно. Доказанное позволяет рассматривать как определение – опр-е той единственной ф., которая этоим треб-ям удовл. Такие определение называется рекурсивным. Заметим, что наше доказательство, по-существу, без изменений и на двум. случ. В частности условия f(0)=a, f(n)=F(n,f(n-1)), при n>0 однозначно определяют ф. f:N->N, каковы бы ни были натуральное число a и ф-я 2-х натуральных аргументов F.
Рекурсивный – значит использующий самого себя. Примеры часто встречаются в жизни. Пр. Выяснение значения слова: 1)найти слово в словаре, 2)прочитать статью, объясняющую значение этого слова, 3)если объяснение понятно, то продолжаем чтение с прерванного места, 4)если в объяснении есть незнакомое слово, то прекращаем чтение текущей статьи, запоминаем место и выясняем значение незнакомого слова, пользуясь правилом «Выяснение значения слова». Рекурсия в программировании: Р., т.е. возможность ввести в опр-е объекта ссылку на сам объект, часто возникает в программировании. Р. – это один из фундаментальных «концептуальных» инструментов, имеющихся в распоряжении программиста. Рекурсивные опр-я часто используются в програм-нии для опред. структур данных.
Пр.type ListPtr= ^List
List = record
info: InfoType;
Next: ListPtr;
end;
или
type
BinTreePtr = BinTree;
BinTree = ^record
info : Information;
left : BinTreePtr;
right: BinTreePtr;
end;
Для обработки «рекурсивных» структур вполне естественным является использование рекурсивных алгоритмов. Пр: Программа вычисления высоты дерева может быть определена как: Высота(t) = {0, если t=nil; 1+max(Высота(left), Высота(right)), если t<>nil}
Свойства рекурс. алгоритмов.1)Прежде всего рекурсия может быть прямой и косвенной:
procedure a(xi…);
begin
B(f(x))
end;
procedure a(yi…);
begin
a(g(y))
end;
2)Другое важное условие, касающееся использования рекурсии, состоит в том, что объекты, порожденные рекурс. опр-ем (будь то инф стр-ры или вычисления) должны быть конечными. Следовательно, вся совок. рекурсивных подпрограмм должна включать такое положение, при котором в определенных частных случаях вычисление могло бы делиться непосредственно, без рекурс. вызова, т.е. одна из подпрогр. должна иметь такой вид:
если с то
Aпрям
иначе
Врекурс
все-если
или
пока не с повторять
Врек
все-пока
Апрям
3) Существует управляющая величина рекурсии m>=0, кот-я убывает с каждым рекурсивным вызовом и когда m=0 рекурс. алг-м завершается.
Этапы рекурс. анализа. Как искать рекурсивные решения? Задача особенно удобна для рекурсивного анализа, если она может быть разложена на совокупность подзадач того же типа, но меньшей размерности. В таком случае общая методика этого анализа (3 этапа): 1)параметризация задачи – заключается в выделении различных элементов, от которых зависит решение и, в частности, размерность решаемой задачи, причем размерность должна (в благоприятных случаях) убывать после каждого рекурсивного вызова, 2)поиск тривиального случая и его решение – зачастую это ключевой этап алгоритма, который может быть решен непосредственно, без рекурсивного вызова. При этом часто размерность задачи нулевая или = 1, 3)декомпозиция общего случая, имеющая целью привести его к одной или нескольким задачам, в основном более простым (меньшей размерности).
Управляющая величина рекурсии. Это некоторая, связанная с этой программой неотрицательная величина m, которая СТРОГО убывает при каждом рекурсивном вызове. В простейшем случае роль такой управляющей величины может играть один из параметров подпрограммы.
Такая программа может иметь вид:
procedure C(n: byte; x,y,z…)
begin
if n=0 then
Априя
else
Bрек
вызов имеет вид:
C(n-1, f(x), g(y), h(z), ….)
. . . . . . . . . .
end
Рекурсия и итерация. Нужно избегать рекурсии, если известно очевидное итеративное решение. Но и уклоняться от рекурсивных решений не надо, т.к. с помощью рекурсии можно зачастую получить более простое и красивое решение.
Исключительные ситуации.
Процедуры в процессе работы преобразуют аргументы в результаты.
Аргументы принадлежат области определения.
Результаты принадлежат области изменения.
Часто процедура имеет смысл только для аргументов, принадлежащих подмножеству её области определения.
Пример:
choose = proc ( S : intset ) returns (int)
requires S - непустой набор intset
effects - возвращает какой-нибудь элемент из S
Операция choose для наборов целых чисел имеет смысл, только если её аргумент - не пустой набор. Пока мы учитываем эту ситуацию, используя процедуру, заданную на некоторой части её области определения.
Тот , кто обращается к такой процедуре, должен гарантировать, что аргументы принадлежат допустимому подмножеству области определения, и тот , кто реализует процедуру, может игнорировать аргументы, не принадлежащие этому подмножеству.
Бывает, однако, что такие процедуры плохи. Компилятор не может гарантировать , что аргументы такой процедуры, как choose, действительно принадлежат допустимому подмножеству, и ввиду этого процедура может быть вызвана с аргументами, не принадлежащими этому подмножеству. Когда это происходит, возникает ошибка, которую очень трудно отследить.
Такие процедуры приводят к не устойчивым программам.
Опр.: Частичная процедура - это процедура определённая не на всей области определения.
Устойчивая программа - это программа, которая ведёт себя корректно даже в случае ошибки. Программа обеспечивает хорошую дегродацию.
Метод. который гарантирует устойчивость, заключается в использовании процедур, заданных на всей области определения. Разрешение ситуации передаётся обратившемуся к процедуре.
Два пути реакции на ошибки:
Осуществить некоторую апроксимацию поведения программы при отсутствии
ошибки.
Остановится; выдать сообщение об ошибке.
Чтобы распознавать ошибки нужно: распознать ошибочную ситуацию; разбить область D = D0 U D1 U . . . U Dn на подмножества, этим подмножествам присвоить имена.
D0 - обычный (R0) }
D1 - имя1 (R1) }
. . . . . . . . . . . . . . . . . } - исключительные ситуации
Dn - имя n (Rn) }
Пример:
choose: D0 - обычный (int)
D1 - empty ( )
Чтобы специфицировать процедуры, которые вызывают исключительные ситуации, добавим в спецификацию предложение signals.
signals % здесь приводится список имен и результатов исключительных
ситуаций.
Это предложение - часть заголовка. Оно следует за предложением returns.
choose = proc ( S : intset ) returns (int) signals (empty)
Это предложение говорит о том, что процедура choose может вызывать исключительную ситуацию empty и что в этом случае не возвращается никакого результата.
search = proc ( a : array [int}, x : int ) returns ( ind : int )
signals ( not_in, duplicete ( indl : int )
Это предложение говорит о том, что процедура search может вызвать две исключительные ситуации: not_in (без результата) и duplicete (результат целое число). Имя indl вводится для ссылок на этот результат в остальной части спецификации.
Как и раньше, секция effects должна определять поведение процедуры для всех фактических аргументов, отвечающих предложению requires. Так как это поведение включает в себя исключительные ситуации, секция effects должна определять, что приводит к вызову каждой исключительной ситуации и что делает процедура в каждом таком случае. Если процедура сигнализирует об исключительной ситуации для аргументов, принадлежащих Di, возможные значения аргументов, принадлежащие Di, не должны присутствовать в предложении requires. Завершение процедуры оповещением об исключительной ситуации - это один из нормальных режимов работы этой процедуры.
Спецификация процедур choose и search.
choose = proc ( S : intset ) returns (int) signals (empty)
signals empty
effects ЕСЛИ S - непустой набор
ТО возвращает какой-нибудь элемент из S
ИНАЧЕ сигнализирует empty
ВСЁ (если)
search = proc ( a : array [int}, x : int )
returns ( ind : int )
signals ( not_in, duplicete ( ind1 : int )
effects ЕСЛИ входит 1 раз
ТО надо написать спецификацию
ИНАЧЕ . . . . . . . и т.д.
D0 - обычный = { < a,x > | x пренадл. a ровно 1 раз }
D1 = { < a,x > | x непрен. a } - not_in
D2 = { < a,x > | x пренадл. a более чем 1 раз } - duplrcate
Программирование с защитой от ошибок называется защитным программированием. При защитном программировании составляют программу так, чтобы она защищала саму себя от ошибок. Данный метод облегчает отладку программ, исключает возможность того , что незначительная ошибка приведет к серьёзной проблеме, как , например , к порче базы данных.
Механизм исключительных ситуаций
в языке CLU.
Язык программирования может сделать работу с исключительными ситуациями легко, если он включает в себя механизм исключительных ситуаций. Этот механизм должен обеспечивать для процедуры возможность сигнализировать об исключительных ситуациях, т.е. доводить их возникновение до сведения использующего процедуру. Кроме того, эту информацию должна быть способна получить вызывающая процедура, чтобы обрабатывать исключительные ситуации.
Процедура , написанная на языке CLU, может завершить работу по одному из некоторого количества условий. В её заголовок включены имена исключительных ситуаций и определены число и типы результатов, возвращаемых в каждом случае. При обычном завершении работы этой процедуры она либо на конец своего тела программы, либо на оператор return.
На примере представлена реализация процедуры choose сигнализирующую об исключительной ситуации.
rep = array [int]
choose = proc ( S : cvt ) returns (int)
signal (empty)
if rep $ size (S) = 0 then
signal empty end
return ( rep $ bottom (S) )
end choose
Обработка исключительных ситуаций.
При завершении работы процедуры с исключительной ситуацией, вызывающая программа должна иметь возможность передать управление программе, которая будет обрабатывать эту исключительную ситуацию.
except список программ обработки ситуаций end.
Список программ обработки исключительных ситуаций включает в себя некоторое подмножество исключительных ситуаций. Каждая программа обработки из списка содержит имена одной или нескольких исключительных ситуаций, за которыми следует список операторов тела программы обработки, определяющих действия, которые должны быть совершены в случае возникновения этих исключительных ситуаций.
Когда возникает исключительная ситуация, программа прекращает свое обычное выполнение и управление передается ближайшему предложению except с программой обработки, имеющей имя этой исключительной ситуации.
Имеется несколько различных форм программ обработки, использование которых связано с тем , имеют ли поименованные исключительные ситуации связанные с ними результирующие объекты и используются ли эти объекты в теле программы обработки. Приведем некоторые примеры.
Пример:
1. Z := x/y
except when
overflow, zerodivicle
Z := 0;
end;
i := search ( a,x )
exept when duplicate ( j : int )
i := j
end
when not_in : end;
Вложенные исключения.
Предложения except могут быть вложенными. Предложение except как целое может внутри самого себя вызвать любые исключительные ситуации, которые не включены в его список программ обработки, плюс любые исключительные ситуации, которые вызывает список программ обработки.
Пример:
indexc_sum = proc ( S : intset; a : array [int] );
returns (int)
signels (problem)
sum : int := 0;
while true do
x : int := intset $ choose (S)
( empty } в choose )
sum := sum + search ( a,x )
( overflow } в sum) ( not_in duplicate } в search )
except when duplicate ( j : int );
sum := sum + j
end;
intset $ delete ( S,x )
end {while}
exept when empty : return (sum)
others : signal problem;
end
end index_sum
Необрабатываемая исключительная ситуация.
failure ( S :string ) - имя возникшей ситуации.
Каждая исключительная ситуация, возникшая в вызванной процедуре и не обрабатывающаяся явно в вызывающей процедуре, автоматически преобразуется в исключительную ситуацию failure. Строковый аргумент содержит имя первой необрабатываемой исключительной ситуации.
Об исключительной ситуации failure может быть сигнализировано явно; в этом случае должен быть задан строковый аргумент.
Ситуация failure обычно означает, что произошла программная или системная ошибка. В этом случае ситуацию обычно анализирует программист. Информация в строке исключительной ситуации предназначена для программиста, а не для программ.
Пример:
Turbo Pascal
{ $ I- }
if IoResult < > 0 then . . . .
VBA
Sub имя_sub ( < . . . >)
On ERROR GOTO имя_sub_err
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
Exit_имя_sub :
Exit_Sub
имя_sub_err :
Textbox Err.Num - номер ошибки
Textbox Err.Description - сообщение (стандартное) об ошибке
Resume
Exit_имя_sub
end Sub
C++
int f ( int arg )
{ try { g (arg)
}
catch (X1) - обработка исключительной ситуации
terminate ( ) - завершать программу
}
Использование исключительных ситуаций в программах.
При реализации процедуры с исключительными ситуациями работа программиста заключается в том, чтобы обеспечить соответствующую спецификации работу процедуры.
Исключительные ситуации могут обрабатываться двумя различными способами. Иногда исключительная ситуация распространяется до другого уровня, т.е. вызывающая процедура также завершает работу сигнализацией об исключительной ситуации с тем же самым или другим именем. Перед распространением исключительной ситуации вызывающая процедура может осуществить некоторую локальную обработку.
Другой способ заключается в том, что вызывающая процедура маскирует исключительную ситуацию, т.е. обрабатывает исключительную ситуацию сама.
Исключительные ситуации следует использовать для устранения большинства ограничений. Также их следует использовать для того , чтобы избежать кодирования информации в обычных результатах.
Когда процедура имеет смысл только для аргументов, принадлежащих подмножеству её области определения, в реализации этой процедуры допускается делать с не принадлежащими этому подмножеству аргументами все, что угодно. Конечно, не все реализации равно хороши. Самый лучший подход - сигнализировать об исключительной ситуации failure. Часто это происходит естественным образом, либо из-за того, что не обрабатывается исключительная ситуация, которая не имеет места для аргументов, принадлежащих допустимому подмножеству, либо из-за выхода на конец процедуры, которая должна возвращать результаты.
Не все ошибки вызывают исключительные ситуации. Например, пусть в большом вводном файле имеется ошибочная запись и будет возможно продолжать обработку файла, пропустив эту запись. В этом случае целесообразно оповестить пользователя ( а не программу ) о произошедшей ошибке. Исключительные ситуации являются механизмом взаимодействия программ, а не программ с пользователями.
Исключительные ситуации не всегда связаны с ошибками. Для некоторых абстракций может быть более чем один тип обычного поведения процедур, и в этом случае исключительные ситуации - удобный инструмент. Они предоставляют средства для обеспечения нескольких типов поведения и дают возможность вызывающему процедуру различать между различными случаями.
Логические спецификации или введение в верификацию программы
Верификация программ осуществляется на основе анализа ее текста. Проводится на основе формул полной коректности. Формула коректности включает в себя предикаты P и Q, а между ними находится сегмент верификационной программы P{S1, ... ,Sn}Q.
P - называется предусловием;
Q - называется постусловием.
Если перед выполнением последовательных операций предикат P выполняется, то гарантируется и выполнение предиката Q, т.е. (FALSE =>P) = TRUE
Пример:
TRUE
{x := 0; y := 1}
y > x
1 > 0 - TRUE
Аксиома для оператора присваивания
Пусть Р есть любой предикат, а е - это выражение свободное от побочных эффектов, тогда если Р истинно после присваивания x := e, то Р с е подставленным во все свободные выражения х перед этими присваиваниями, должен быть истинен.
P[e -> x] {x := e}P
Пример:
x > n {x := x + 1} x > n + 1
x > n => x + 1 > n + 1
x > n => x > n
TRUE
Способы доказательства. Методы прохода вперед и назад.
Метод рохода назад приводит к получению предусловия, т.е. выполнения его достаточно для получения результата и его включает в себя любое достаточное предусловие.
Метод прохода вперед сводится к тому, что двигаясь от предусловия мы доказываем самое сильное постусловие, т.е. оно включает и требуемое нами постусловие.
P{ S }Q
Аксиома последовательного выполнения.
Если P{ А }Q и Q{ B }R, то выполняется P{ A;B }R
Пример:
(0 < x < 1) {x := 1/x + y; x := x + 1} (x > y + 2)
(0 < x < 1) {x := 1/x + y} (x + 1 > y + 2)
(0 < x < 1) {x := 1/x + y} (x > y + 1)
Обозначим n = y + 1.
(0 < x < 1) {x := 1/x + y} (x > n)
( x > n) {x := x + 1} (x > n + 1) => TRUE
Аксиома ветвления.
Если некоторое условие В не имеет побочных эффектов, то доказательства
P{ if B then S1 else S2}Q
эквивалентно доказательству пары
P&B{ S1 }Q и P&B{ S2 }Q
Пример:
(x > 0)&(y = 0)
{while (y = x) do y := y + 1}
(y = x)