Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Теоретическая информатика. Доказательство правильности. Учебное пособие
.pdf
доказывающим устройством), то ему можно было бы полностью доверять. В будущем это, возможно, окажется реальным, но не сейчас.
Мы рассмотрим лишь неформально построенные доказательства правильности. Опыт проведения таких доказательств показывает, что
при этом возрастают наша уверенность в программе и ее понимание,
и поэтому доказательства следует выполнять, хотя они и
не приводят
к полной гарантии от ошибок. Неформальное доказательство правильности можно рассматривать как некоторую форму систематической проверки программы за столом, без машины, т. е. того, что всегда делает хороший программист. В этой главе даны основные идеи
такого доказательства правильности для программ, представленных
блок-схемами.
2.1. ОСНОВНЫЕ ПРИНЦИПЫ ДОКАЗАТЕЛЬСТВА
ПРАВИЛЬНОСТИ БЛОК-СХЕМ
Если мы хотим доказать, что некоторая программа правильна или
верна, то прежде всего должны уметь описать то, что, по нашему
предположению, делает эта программа. Назовем такое описание высказыванием о правильности или просто утверждением. В этом слу-
чае доказательство правильности состоит из доказательства того, что
программа, будучи запущенной, в конце концов
окончится (выполнится оператор STOP), и после окончания программы будет справедливо
утверждение о правильности. Часто требуется, чтобы программа работала правильно только при определенных значениях входных данных.
В этом случае доказательство правильности состоит из доказательства
того, что если программа выполняется при соответствующих входных
данных, то она когда-либо закончится, и после
этого будет справедли-
во утверждение о правильности.
Алгоритм доказательства правильности блок-схемы включает сле-
дующие шаги.
1. Расставить на блок-схеме контрольные точки.
2. Сформулировать и приписать к соответствующим точкам четыре
индуктивных утверждения (утверждение о входных данных, инвариант
цикла, утверждение о конечности цикла и утверждение о правильности), причем инвариант цикла выводится
с помощью трассировочной
таблицы.
3. Доказать инвариант цикла с помощью простой индукции.
4. Неформально доказать утверждение о конечности.
11

5. Доказать, что из инварианта цикла и утверждения о конечности
следует утверждение о правильности.
Проиллюстрируем эти идеи на примере доказательства правильно-
сти блок-схемы очень простой программы.
Пример 2.1. Докажем, что приведенная на рис. 2 блок-схема пра-
вильна, т. е. если ее начать выполнять с M и N, имеющими некоторые
целые значения, причем M 0, то выполнение в конечном итоге закончится с J = M N.
Рис. 2
12

Вначале докажем, что при попадании в точку 2 J = I N.
1. При первом попадании в точку 2 при переходе из точки 1 имеем
I = 0 и J = 0. Таким образом, утверждение J = I N = 0 N = 0 спра-
ведливо.
2. Предположим, что мы попали в точку 2 и утверждение J = I N
справедливо. Пусть I и J в этой точке принимают значения I
т. е. J
= IN N. Предположим теперь, что мы прошли по циклу (от
N
и JN,
N
точки 2 через точки 3, 4 вновь в точку 2). При возвращении в точку 2
I и J принимают новые значения I
N+1
и J
, которые можно предста-
N+1
вить следующим образом:
I
= IN + 1,
N+1
J
= IN N+ N = (IN + 1) N = I
N+1
N. (Так как JN = IN N.)
N+1
Следовательно, при очередном попадании в точку 2 высказывание
J = I N вновь справедливо, что и требовалось доказать, т. е. при лю-
бом попадании в точку 2 справедливо высказывание J = I N.
Теперь докажем, что в конце концов попадем в точку 2 со значени-
ем I = M.
При первом попадании в точку 2 имеем I = 0. При последующих попаданиях, если таковые есть, I каждый раз увеличивается
на 1. Так как значение M нигде в программе не изменяется и мы
предположили, что M 0, то очевидно, что в какой-то момент I станет равным M.
Если мы попадем в
точку 2 при I = M, то будет верно и J = I N =
= M N. Отношение I = M в этот момент истинно, и мы попадаем по
стрелке с пометкой Т (TRUE – истина) в точку 5 с J = M N. На этом
доказательство правильности программы заканчивается.
Пример 2.2. Докажем правильность программы вычисления целого
частного IQ и остатка IR от деления J1 на J2, где J1 и J2 – любые
два целых числа, удовлетворяющие условиям 0 J1 и 1 J2. Операция
деления в программе для вычисления IQ и IR не используется. Один
из способов указать, что делает программа, – сказать, что
она вычис-
ляет два целых числа IQ и IR, таких, что J1/J2 = IQ + IR/J2 и
0 IR < J2. Это можно записать так: J1 = IQ J2 + IR и 0 IR < J2.
Как и выше, свяжем непосредственно с блок-схемой программы
(рис. 3) допущения о входных данных и те утверждения
, правильность
которых требуется доказать.
13

Рис. 3
Отметим, что допущения о считываемых значениях для J1 и J2
мы поставили непосредственно после ввода. Это указывает на то, что
правильность работы программы будет доказываться только для данных, удовлетворяющих этому допущению. Утверждение о правильности блок-схемы связано с ее последней точкой. Кроме того, с начальной точкой цикла связываются
два основных факта, которые требуется
доказать. Теперь проследим за работой программы с символическими
данными для J1 и J2 и выясним, как ведут себя инварианты цикла
(основные утверждения о цикле):
14

Число проходов Значение IQ Значение IR
через точку 2
1 0 J1
2 1 J1 – J2
3 2 J1 – 2 J2
4 3 J1 – 3 J2
… … …
. . Пока IR < J2
Отметим, что при каждом попадании в точку 2
IR = J1 – IQ J2, или J1 = IQ J2 + IR.
Это утверждение идентично утверждению о правильности, за
исклю-
чением того, что последнее еще включает условие 0 IR < J2. Таким
образом, остается лишь показать, что цикл когда-нибудь закончится и
при этом будет выполняться условие 0 IR < J2. Легко установить, что
высказывания, связанные с точкой 2, утверждают именно эти факты о
цикле.
Для доказательства правильности программы сначала покажем,
, как только мы попадем в точку 2, J1 = IQ J2 + JR.
что
1. При первом проходе через точку 2, двигаясь от точки START к
точке 2, имеем IQ = 0 и IR = J1, т. е. утверждение J1 = IQ J2 + IR =
= 0 J2 + J1 = J1 справедливо.
2. Предположим, что выполнение программы дошло до точки
2 и
справедливо утверждение J1 = IQ J2 + IR. Пусть IQ и IR в этот
момент принимают значения IQ
положению утверждение записывается так: J1 = IQ
и IRN. Наше справедливое по пред-
N
J2 + IRN (гипо-
N
теза индукции). Пройдем один раз по циклу (от точки 2 через точки 3,
4 опять в точку 2). При возвращении в точку 2 новые значения IQ и
IR будут такими: IQ
IQ
J2 + IR
N+1
= IQ
J2 + J2 + IRN – J2 = IQN J2 + IRN = J1
N
N+1
= IQN + 1 и IR
N+1
= (IQN + 1) J2 + (IRN – J2) =
= IRN – J2. Таким образом,
N+1
| По гипотезе индукции |.
Что и требовалось доказать, т. е. при попадании в точку 2 справед-
ливо высказывание J1 = IQ J2 + IR.
Докажем, что в конце концов мы попадем в точку 2 при условии
0 IR < J2. Для этого покажем вначале, что при всяком проходе через
точку 2 имеем 0 IR.
15

1. При первом проходе через точку 2 имеем IR = J1 и по предпо-
J
X
J
X
ложению 0 J1. (Отметим, что это единственное место в доказатель-
стве, где используется данное предположение. Таким образом, если бы
мы не потребовали IR 0, то блок-схема должна была бы работать
правильно даже для отрицательных значений J1.)
2. Предположим,
момент IR принимает значение IR
вновь в точку 2, то IR примет новое значение IR
что мы попали в точку 2 и 0 IR. Пусть в этот
. Если мы через цикл вернемся
N
= IRN – J2. Но через
N+1
цикл мы пройдем только в случае отрицательного ответа на проверку
< J2, т. е. если истинно отношение J2 IRN. Но если J2 IRN, то
IR
N
0 IR
– J2 = IR
N
истинно. Таким образом, мы доказали, что 0 IR
N+1
при каждом попадании в точку 2.
Докажем затем, что в конечном итоге мы попадем в точку 2 при
справедливом условии IR < J2 (т. е. в этом случае мы будем иметь
0 IR < J2). Отметим, что при каждом проходе через цикл значение IR
уменьшается на значение J2. Так как значение J2 в программе нигде
не изменяется и 1 J2, то, очевидно, при каждом повторении процесса IR уменьшается, по крайней мере, на 1. Следовательно, в конце
концов значение IR должно стать меньше J2 (с помощью метода
индукции это можно доказать более строго).
Таким образом,
в какой-то момент мы попадем в точку 2 со спра-
ведливыми условиями 0 IR < J2 и J1 =IQ J2 + IR. В этот момент
условие IR < J2, естественно, истинно и из точки 2 мы идем в точку 5,
а затем в точку 6. Так как на пути из точки 2
в точку 6 ни одна переменная не изменяется, то очевидно, что в момент прихода в точку 6
утверждение о правильности будет справедливо. Следовательно, мы
доказали, что при выполнении программы с целыми J1 и J2, удовлетворяющими условиям 0 J1 и 1 J2, программа в какой-то момент
закончится и
будут справедливы отношения J1 = IQ J2 + IR
и 0 IR < J2, т. е. IQ и IR будут целыми частным и остатком от деления J1 на J2.
Пример 2.3. Мы хотим доказать, что приведенная на рис. 4
блок-схема обеспечивает правильное вычисление суммы
N
XX X
. Покажем, что при каждом попадании в точ-
1
J
12
ку 2 выполняются соотношения 1 I N + 1 и
...
N
1
I
...
XX
.
J
1
11
I
16

1. При первом попадании в точку 2 имеем I = 1 и SUM = 0;
J
X
следовательно, утверждения, что 1 I < N + 1 и SUM =
10
I
XX
=
JJ
JJ
11
0
справедливы.
Рис. 4
2. Предположим, что мы находимся в точке 2 и 1 I N + 1
11I
и SUM =
справедливы. Пусть I и SUM в этой точке прини-
J
17

1
I
J
X
J
X
J
X
J
X
J
I
мают значения IN и SUMN, т. е . 1 IN N + 1 и =
...
чим I
II I
nn n
=
JJ J
. Если мы пройдем по циклу и вернемся в точку 2, то полу-
1
IX
n
= IN + 1 и SUM
N+1
(1)1 1
11 1
XX
JJ
1
= SUMN +
N+1
.
X
( ... )
XXX
+
n
11
n
XX
J
1
J
II
nn
...
1
Кроме того, если цикл повторялся, то проверка IN N давала по-
ложительный ответ, а так как истинно и утверждение 1 I
то, следовательно, 1 I
имеем 1 < 2 I
+ 1 = I
N
утверждений 1 I N + 1 и SUM =
N. Но в этом случае при возврате в точку 2
N
N + 1. Таким образом, справедливость
N+1
11I
при прохождении точки 2
J
N + 1,
N
доказана.
Легко видеть, что если 1 N, то переменная I, увеличиваясь с 1
каждый раз на 1, в конце концов станет равной N + 1. В этот момент
проверка даст отрицательный ответ и мы попадем в точку 4, где имеем
11I
SUM =
и I = N + 1, или, что тоже самое, SUM =
J
(1)1
NN
X
JJ
11
J
Таким образом, мы доказали, что работа программы (достигнув точки 4)
N
прекратится и SUM =
JX
.
1
Пример 2.4. Мы хотим доказать, что приведенная на рис. 5 блок-
схема вычисляет и печатает среднее значение и максимальное из всех
чисел во входном файле. Сначала докажем, что справедливо утверждение, связанное с точкой 2.
1. Если программа выполняется с входным файлом, содержащим
одно и более вещественных чисел, то можно выполнять первый блок
так как входной файл не пуст), и при первом попадании в точку 2 зна-
(
чение N равно 1, а значение XLGST и SUM – первые числа в исходном
входном файле. Таким образом, при первом достижении точки 2
утверждения о N, XLGST и SUM справедливы.
.
18

Рис. 5
2. Предположим, что мы находимся в точке 2 и утверждения о N,
XLGST и SUM справедливы. Нужно показать, что, если мы пройдем по циклу и вернемся в точку 2, эти утверждения будут оставаться
19

верными. Отметим, что при прохождении цикла в X считывается
очередное значение из входного файла (файл по определению не
пуст, иначе цикл не выполнялся бы), значение N увеличивается на 1,
а значение SUM становится SUM + Х. Поэтому при возврате в точку 2 значение N вновь указывает число считанных из входного файла данных (больше предыдущего на 1), а
значение SUM вновь будет
суммой всех считанных из файла чисел (сумма всех предварительно
считанных чисел плюс последнее прочитанное число). Затем при
каждом выполнении цикла переменная XLGST (мы предполагаем,
что это наибольший из всех считанных элементов) сравнивается с
новым элементом, считанным последним в X из файла. Если отношение Х XLGST истинно, то по
блок-схеме XLGST не изменяется, и это верно, так как ее значение представляет собой самое
большое число из всех считанных из файла. Если же отношение
Х XLGST ложно, то последний считанный элемент – самый большой из всех считанных, и поэтому в блок-схеме предусмотрена запись значения X в XLGST. Таким образом, при
возврате в точку 2
(пройдем ли мы в нее через точки 2, 3, 4 или через точки 2, 3, 5, 6)
XLGST всегда будет наибольшим из всех считанных до этого значе-
ний, что и требовалось доказать, т. е. при каждом проходе через точку 2 утверждения, касающиеся N, XLGST и SUM, справедливы.
Ясно, что
в конце концов мы попадем в точку 2, когда во входном
файле не останется больше элементов, которые можно было бы прочитать. Это произойдет потому, что при каждом прохождении цикла считывается один очередной элемент файла, а мы (неявно) предполагали,
что входной файл содержит конечное число элементов. Следовательно,
после конечного
числа прохождений через цикл все элементы входного файла будут прочитаны. После этого проверка на конец файла даст
ответ ДА и мы выйдем из цикла, имея следующие значения: N – число
элементов чисел, считанных на данный момент; XLGST – наибольший
из всех элементов в исходном входном файле; SUM – сумма всех элементов в исходном входном файле
.
При попадании в точку 8 переменная AVG будет иметь значение AVG = SUM/N, a XLGST – то же значение, которое указано
выше. Таким образом, работа программы в конце концов закончится, и, когда это произойдет, AVG и XLGST будут иметь требуемые значения.
20
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
