Главная страница
Навигация по странице:

  • AND NOT

  • ТЕОРИЯ ВЫЧИСЛИТЕЛЬНЫХ СИСТЕМ. Теория вычислительных процессов


    Скачать 2.17 Mb.
    НазваниеТеория вычислительных процессов
    АнкорТЕОРИЯ ВЫЧИСЛИТЕЛЬНЫХ СИСТЕМ.doc
    Дата01.04.2018
    Размер2.17 Mb.
    Формат файлаdoc
    Имя файлаТЕОРИЯ ВЫЧИСЛИТЕЛЬНЫХ СИСТЕМ.doc
    ТипДокументы
    #17485
    страница9 из 20
    1   ...   5   6   7   8   9   10   11   12   ...   20

    DO: do B1 → S1 П B2 → S2 ... П Bn → Snod,

    где n  0, Bi → Si- охраняемые команды.

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

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

    Следовательно, оператор DO эквивалентен оператору

    do BBif B2S1 П B2S2 ... П Bn → Snfi od или do BBIF od,

    где BB - дизъюнкция охран, IF - оператор выбора.

    Пример 2.5. Алгоритм Евклида.

    Вариант 1.

    задать (N, M);

    if N > 0 AND M > 0 → n, m := N, M;

    do n ≠ mif n > m → n := n – m П m > n → m := m – n fi od;

    выдать (n)

    fi.

    Вариант 2.

    задать (N, M);

    if N > 0 AND M > 0 → n, m := N, M;

    do n > m → n := n – m П m > n → m := m – n od;

    выдать (n)

    fi.

    Дадим формальное определение слабейшего предусловия для оператора цикла DO.

    Пусть предикат H0(R) определяет множество состояний, в которых выполнение DO завершается за 0 шагов (в этом случае все охраны с самого начала ложны, после завершения R имеет значение истина):

    H0(R) = NOT BB AND R.

    Другими словами, требуется, чтобы оператор цикла DO завершил работу, не производя выборки охраняемой команды, что гарантируется первым конъюнктивным членом предиката H0(R): NOT BB = T. При этом истинность R до выполнения DO является необходимым условием для истинности R после выполнения DO.

    Определим предикат Hk(R) как множество состояний, в которых выполнение DO заканчивается за k шагов при значении R истина (Hk(R) будет определяться через Hk-1(R)):

    Hk(R) = H0(R) OR wp(IF, Hk-1(R)), k > 0 → wp(DO, R) = ( k: k  0: Hk(R)).

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

    Определение DO. Если предикаты Hk(R) задаются в виде

    Hk(R) = NOT B AND R, k= 0,

    Hk(R) = wp(IF, Hk-1(R)), k > 0, → wp(DO, R)=( k: k  0: Hk(R)).

    Основная теорема для оператора цикла. Пусть оператор выбора IF и предикат P таковы, что для всех состояний справедливо

    (P AND BB) => wp(IF, R).(2.3)

    Тогда для оператора цикла справедливо:

    (P AND wp(DO, T)) => wp(DO, P AND NOT BB).

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

    Поясним смысл теоремы. Условие (2.3) означает, что если предикат P первоначально истинен и одна из охраняемых команд выбирается для выполнения, то после ее выполнения P сохранит значение истинности. После завершения оператора, когда ни одна из охран не является истиной, будем иметь:

    P AND NOT BB.

    Работа завершится правильно, если условие wp(DO, T) справедливо и до выполнения DO. Так как любое состояние удовлетворяет T, то wp(DO, T) является слабейшим предусловием для начального состояния такого, что запуск оператора цикла DO приведет к правильно завершаемой работе.

    Доказательство.

    Из определения DO следует:

    H0(T) = NOT BB AND T, k = 0;

    Hk(T) = wp(IF, Hk-1(T)), k > 0, → wp(DO, T) = ( k: k  0: Hk(T));

    H0(P AND NOT BB) = P AND NOT BB;

    Hk(P AND NOT BB) = wp(IF, Hk-1(P AND NOT BB), → wp(DO, P AND NOT BB) = = ( k  0: Hk(P AND NOT BB)).

    С помощью метода математической индукции можно доказать, что из условия (2.3) следует

    (P AND Hk(T)) => Hk(P AND NOT BB), k  0.

    Тогда имеем

    P AND wp(DO, T) = ( k: k  0: P AND Hk(T)) => ( k: k  0: Hk(P AND NOT BB)) = = wp(DO, P AND NOT BB).

    Следовательно, (P AND wp(DO, T)) => wp(DO, P AND NOT BB).

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

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

    Для интерпретации системы функций (2.1) вводится понятие аксиоматического описания <S, A> - логически связанной пары понятий: S - сигнатура используемых в системе символов функций f1, f2, ..., fm и символов констант (нульместных функциональных символов) c1, c2, ..., cl, а A - набор аксиом, представленный системой. Предполагается, что каждая переменная xi, i = 1, ..., k, и каждая константа ci, i = 1, ..., l, используемая в A, принадлежит к какому-либо из типов данных t1, t2, ..., tr, а каждый символ fj, j = 1, ..., m, представляет функцию, типа: ti1 ti2t... ik ti0. Такое аксиоматическое описание получит конкретную интерпретацию, если будут заданы конкретные типы данных ti = ti', i = 1, ..., r, и конкретные значения констант ci = ci', i = 1, ..., l.

    К. Хоaр построил аксиоматическое определение набора типов данных, которые потом Н. Вирт использовал при создании языка Паскаль.

    Пример 2.6. Рассмотрим систему равенств:

    УДАЛИТЬ(ДОБАВИТЬ(m,d)) = m,

    ВЕРХ(ДОБАВИТЬ(m,d)) = d,

    УДАЛИТЬ(ПУСТ) = ПУСТ,

    ВЕРХ(ПУСТ) = ДНО,

    где УДАЛИТЬ, ДОБАВИТЬ, ВЕРХ - символы функций, а ПУСТ и ДНО - символы констант, образующие сигнатуру этой системы. Пусть D, D1 и М - некоторые типы данных, такие, что m M, d D, ПУСТ M, ДНО D1, а функциональные символы представляют функции следующих типов:

    УДАЛИТЬ: M M,

    ДОБАВИТЬ:M, D M,

    ВЕРХ:M D1.

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

    Зададим интерпретацию символов ее сигнатуры: D - множество значений, которые являются элементами магазина, M - множество состояний магазина, M = {d1,d2, ... ,dn: di D, i= 1, ..., n, n 0}, D1=D {ДНО}, ПУСТ={}, а ДНО - особое значение (зависящее от реализации магазина), не принадлежащее D. Тогда указанный набор аксиом определяют свойства магазина.

    При определении семантики полного языка программирования с использованием аксиоматического метода для каждого вида операторов языка должны быть сформулированы аксиома или правило логического вывода. Но определение аксиом и правил логического вывода для некоторых операторов языков программирования - очень сложная задача. Трудно построить «множество основных аксиом, достаточно ограниченное для того, чтобы избежать противоречий, но достаточно богатое для того, чтобы служить отправной точкой для доказательства высказываний о программах» (Э. Дейкстра).

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

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

    Основной концепцией денотационной семантики является определение для каждой сущности языка некоего математического объекта и некоей функции, отображающей экземпляры этой сущности в экземпляры этого математического объекта. Поскольку объекты определены строго, то они представляют собой точный смысл соответствующих сущностей. Сама идея основана на факте существования строгих методов оперирования математическими объектами, а не конструкциями языков программирования. Сложность использования этого метода заключается в создании объектов и функций отображения. Название метода «денотационная семантика» происходит от английского слова denote(обозначать), поскольку математический объект обозначает смысл соответствующей синтаксической сущности.

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

    <двоичное_число> → 0; | 1; | <двоичное_число>0; | <двоичное_число>1.

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

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

    Пусть область определения семантических значений объектов представляет собой множество неотрицательных десятичных целых чисел Nat. Это именно те объекты, которые мы хотим связать с двоичными числами. Семантическая функция Мb отображает синтаксические объекты в объекты множества N согласно указанным выше правилам. Сама функция Мbопределяется следующим образом:

    Мb('0') = 0, Мb('1')=1;

    Мb(<двоичное_число> '0') = 2 × Мb(<двоичное_число>);

    Мb(<двоичное_число> ‘1’) = + 2 × Мb(<двоичное_число>) + 1.

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

    Пример 2.7. Описание значения десятичных синтаксических литеральных констант.

    <десятичное_число> → 0|1|2|3|4|5|6|7|8|9;

    | <десятичное_число> (0|1|2|3|4|5|6|7|8|9).

    Денотационные отображения для этих синтаксических правил имеют следующий вид:

    Md(‘0') = 0, Md('1') = 1, ,..., Md('9') = 9;

    Мd(<десятичное_число> '0') = 10 × Мd(<двоичное_число>);

    Мd(<десятичное_число> ‘1’) = 10 × Мd(<десятичное_число>) + 1;



    Мd(<десятичное_число> '9') = 10 × Мd(<десятичное_число>) + 9.

    Денотационную семантику программы можно определить в терминах изменений состояний идеального компьютера. Подобным образом определялись операционные ceмантики, приблизительно так же определяются и денотационные. Правда, для простоты они определяются только в терминах значений всех переменных, объявленных в программе. Операционная и денотационная семантики различаются тем, что изменения состояний в операционной семантике определяются запрограммированными алгоритмами, а в денотационной семантике они определяются строгими математическими функциями. Пусть состояние s программы определяется следующим набором упорядоченных пар: {<i1, v1>, <i2, v2>, …, <in, vn>}.

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

    Пусть VARMAP - функция двух параметров, имени переменной и состояния программы. Значение функции VARMAP(ik, s) равно vk(значение, соответствующее параметру ik в состоянииs).

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

    Выражения являются основой большинства языков программирования. Более того, мы имеем дело только с очень простыми выражениями. Единственными операторами являются операторы + и ×; выражения могут содержать не более одного оператора; единственными операндами являются скалярные переменные и целочисленные литеральные константы; круглые скобки не используются; значение выражения является целым числом. Ниже следует описание этих выражений в форме БНФ:

    <выражение> → <десятичное_число>| <переменная>

    | <двоичное_выражение>

    <двоичное_выражение> → <выражение_слева><оператор>

    <выражение_справа>

    <оператор> → + | ×

    Единственной рассматриваемой нами ошибкой в выражениях является неопределенное значение переменной. Разумеется, могут появляться и другие ошибки, но большинство из них зависят от машины. Пусть Z - набор целых чисел, a error - ошибочное значение. Тогда множество Z {error} является множеством значений, для которых выражение может быть вычислено.

    Ниже приведена функция отображения для данного выражения Е и состояния s. Символ  обозначает равенство по определению функции.

    Me(<выражение>, s) 
    1   ...   5   6   7   8   9   10   11   12   ...   20


    написать администратору сайта