Смекни!
smekni.com

Лекции по информатики 2 (стр. 28 из 43)

Для обоснования правильности алгоритма докажем вспомогатель­ное утверждение о результатах выполнения конструкции альтерна­тивного выбора

Лемма: Конечными результатами выполнения алгоритма

АлгоритмРезультаты

если а > b топри а ³ b

тх:= аmx = a

иначепри b > a

тх := b mx = b

кесли

является значение mx = max(а, b) для любых значений а и b.

Доказательство. Результатом вычислений здесь будут значения

а при а ³ b

mx =

b при а < b

что совпадает с определением max (а, b).

С помощью этой леммы легко доказать правильность алгоритма в целом.

{ mх = max (а, b) } Результаты

если с ³ mx топри с ³ mx

mx:= сmx' = с

кеслиmx' = mx

при с < mx

Утверждение. Конечным результатом выполнения алгоритма вы­числения максимума будет значение mx' = max (а, b, с) для любых значений а, b и с.

Доказательство. В силу предположения предшествующее значе­ние переменной mx = max(a,b). Отсюда получаем, что

с, при с ³ mx

mx¢ = = max(a,b,c).

mx, при с < mx

Что и требовалось доказать.

Доказательство лемм - основной прием доказательства правиль­ности сложных алгоритмов и программ. Напомним, что лемма — это вспомогательное утверждение, предполагающее отдельное доказа­тельство.

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

В качестве примера использования индуктивных рассуждений рассмотрим алгоритм вычисления среднего арифметического после­довательности чисел. В приводимом алгоритме предполагается, что последовательность чисел размещена в массиве X[1:N].

алг «среднее значение»

массив X[1:N]

начРезультаты:

от k = 1 до N цикл

S := S * (k-l)/k + X[k]/k Sk = Sk-1*(k-l)/k + X[k]/k

кцикл [k = (1...N)]

Xcp := S Xcp = S

кон

Этот алгоритм обычно считается ошибочным (?!). «Ошибкой» в этом алгоритме считается отсутствие присваивания S := 0 перед началом цикла.

Разберем результаты выполнения алгоритма на первых трех ша­гах:

S1 = S0×(l - 1)/1 + Х[1]/1 = S0×0/1 + Х[1]/1 = Х[1]/1;

S2 = S1×(2 - 1)/2 + Х[2]/2 = S1×1/2 + Х[2]/2 = Х[1]/2 + Х[2]/2;

S3 = S2×(3 - 1)/3 + Х[3]/3 = S2×2/3 + Х[3]/3 = Х[1]/3 + Х[2]/3 + Х[3]/3.

Можно утверждать, что на первых трех шагах результатом является среднее арифметическое обрабатываемых чисел. На основе этих примеров можно сделать индуктивное утверждение - «на каждом очередном k-м шаге выполнения цикла результатом будет среднее арифметическое»

Sk = Sk-1×(k-l)/k + X[k]/k = X[l]/k + X[2]/k + ... + X[k]/k.

Доказательство этого утверждения проводится с помощью мате­матической индукции. На первом шаге при k = 1 оно уже доказано. Допустим, что оно справедливо на (k -1)-м шаге

Sk-1 = X[l]/(k-l) + X[2]/(k-l) + ... + X[k-l]/(k-l).

Подставим его в описание результатов цикла на k-м шаге

Sk= Sk-1×(k-l)/k +X[k]/k.

Тогда результат выполнения цикла на k-м шаге оказывается рав­ным

Sk = X[l]/k + X[2]/k + ... + X[k-l]/k + X[k]/k,

т. е. среднему арифметическому первых k чисел.

Таким образом, индуктивное утверждение доказано. В силу мате­матической индукции это утверждение верно для всех k = l, 2, ..., N. Следовательно, на последнем шаге конечным результатом выполнения цикла станет значение

SN = SN-1×(N-1)+ X[N]/N = X[1]/N + ... + X[N]/N.

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

Xcp = SN= X[1]/N + ... + X[N]/N.

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

Индукция - это вывод общих суждений из частных примеров. При анализе циклов она используется для подбора индуктивных утверждений о промежуточных результатах выполнения циклов. Однако для доказательства правильности индуктивных утверждений о результатах выполнения циклов используется полная математи­ческая индукция.

Математическая индукция - это принцип доказательства после­довательностей утверждений Р(1), Р(2), Р(3), ..., P(N), .... когда известно, что верны первые утверждения для n = 1, 2, 3 и из истин­ности (n - 1)-го утверждения следует истинность n-го утверждения:

Принцип математической индукции: если первое утверждение Р(1) истинно и из утверждения Р(n - 1) следует утверждение Р(n), то истинны все утверждения Р(1), Р(2), Р(3), ..., Р(n), ... .

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

алг «нахождение минимума»

массив x[1:N]

начРезультаты:

от k = 1 до N цикл

если x[k] < min то

тп := x[k] mnk = { x[k], при x[k] < mnk-1,

все{ mnk-1, в ином случае

кцикл[ k = (1 ... N)]

Min := тпMin = mnN

кон

Утверждение. Приведенный алгоритм определения минимального значения последовательности чисел неправильный.

Доказательство. Для демонстрации ошибок необходимо привести контрпример. Для построения контрпримера разберем результаты выполнения на первом шаге цикла.

Результаты выполнения первого шага цикла при k = 1:

х[1] при х[1] < mn0

mn1== min (х[1], mn0).

mn0 при х[1] £ mn0

Следовательно, результатом будет

mn1 = min (x[l], mn0)

Однако поскольку начальное значение mn0 неизвестно, то не­определено значение результата выполнения первого шага цикла. Аналогичное утверждение можно сделать о втором и всех последу­ющих шагах выполнения цикла:

mnk = min (x[k], Min(x[k-l], ..., х[1], mn0) = Min (x[k], x[k-1], ..., х[1], mn0).

В силу математической индукции это утверждение справедливо при k = N:

mnN = Min (x[N], x[N - 1], ..., x[2], х[1], mn0),

Таким образом на основании этого утверждения можно сделать заключение о конечном результате выполнения алгоритма в целом:

Min = mnN = Min (x[N], x[N - 1], ..., x[2], х[1], mn0).

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

В самом деле, если значение mn0 окажется меньше любого из значений последовательности х[1], .... x[N], то конечный результат вычислений будет неправильным. В частности, при реализации алгоритма на Бейсике неправильный результат будет получен, если последовательность будет состоять только из положительных чисел. Например, для последовательности чисел: 1, 2, 3, ..., N.

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

алг «нахождение минимума»массив х[1:п]нач тп := x[1] от k = 1 до N цикл если x[k] < тп то тп = x[k] все кцикл Min = тпкон
Результаты:mn0 = х[1] [k = (1 ... N)]
Min = mnN

Утверждение. Для любой последовательности чисел x[l:N] конечным результатом вычислений будет значение Min = Min (х[1], ..., x[N]).

Доказательство. Воспользуемся результатами анализа выполнения алгоритма, рассмотренного ранее. Различие между ними состоит в добавлении перед началом цикла присваивания mn := х[1], которое задает начальное значение переменной mn, равное mn0 = х[1].

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

Min = mnN = Min(x[N], x[N-l], ..., х[2], х[1], mn0) =

= Min(x[N], x[N-l], ..., x[2], x[l], x[l]) = Min(x[N], .... х[1]).

Что и требовалось.

Рассмотренные примеры являются образцами доказательств пра­вильности алгоритмов и программ, которые могут использоваться для анализа и доказательства правильности других новых алгоритмов и программ обработки данных.

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