Первоначально по математике. Но там без ответа.
Рассмотрим следующий алгоритм.
u := 0
v := n+1;
while ( (u + 1) is not equal to v) do
x := (u + v) / 2;
if ( x * x <= n)
u := x;
else
v := x;
end_if
end_while
где u, v и n - целые числа, а операция деления - целочисленное деление.
- Объясните, что вычисляется по алгоритму.
- Используя ваш ответ на часть I в качестве пост-условия для алгоритма, установите инвариант цикла и покажите, что алгоритм завершается и корректен.
В классе было найдено, что равно а инвариант - . Я не очень понимаю, как были получены постусловие и инварианты. Я полагаю, что почтовое условие было ... что явно не так. Поэтому мне интересно, как был получен постусловие и инвариант. Мне также интересно, как предварительное условие может быть получено с помощью постусловия.
Ответы:
Жиль прав, что основная техника - ловить рыбу для интересных наблюдений.
В этом случае вы можете заметить, что программа является экземпляром бинарного поиска, потому что она имеет следующую форму:
Затем вы просто подключаете свой конкретный
f
,X
... в общий инвариант для бинарного поиска. У Дейкстры хорошее обсуждение бинарного поиска .источник
break
: при выходе из цикла это может быть только потому, что условие цикла (здесь ) является ложным. Это не единственное, что будет верно, когда цикл выйдет отсюда (этот алгоритм фактически вычисляет что-то интересное, как вы видели в своем классе, так что и также являются постусловиями), но это наиболее очевидно.Теперь, чтобы найти другие интересные свойства, нет общего рецепта. На самом деле, существует некоторый формальный смысл, в котором нет общего рецепта для поиска инвариантов цикла. Лучшее, что вы можете сделать, - это применить некоторые методы, которые работают только в некоторых случаях, или вообще ловить рыбу для интересных наблюдений (которые работают все лучше и лучше, когда вы становитесь более опытными).
Если вы запустите цикл для нескольких итераций с некоторым значением , вы увидите это на каждой итерации:n
В частности, начинаете меньше, чем , и никогда не обгоните его. Кроме того, начинается с положительного значения и увеличивается, а начинается с и уменьшается. Таким образом, является инвариантом всей этой программы.u v u v n+1 0≤u≤v≤n+1
Одна вещь, которая не так очевидна, - может ли когда-либо быть равен . Это важно: если и когда-нибудь станут равными, у нас будет и цикл будет продолжаться вечно. Таким образом, вам нужно доказать, что и никогда не становятся равными, чтобы доказать, что алгоритм корректен (то есть не зацикливается вечно). Как только эта потребность была определена, легко доказать (я оставляю это как упражнение), что является инвариантом цикла (имейте в виду, что и являются целыми числами, так что это эквивалентно ).u v u v x=u=v u v u<v u v u+1≤v
Поскольку в конце программы, заданное вами постусловие также можно записать как (часть тривиальна). Причина, по которой нам нужно подобное пост-условие с участием , заключается в том, что мы хотим связать результат программы с входом . Почему это точное условие? Мы ищем что-то максимально точное и смотрим, где появляется внутри цикла:v=u+1 u2≤n<v2 0≤u2 n n n
Эта дихотомия намекает на то, что, возможно, все время. Другими словами, мы подозреваем, что это инвариант цикла. Проверка этого оставлена читателю как упражнение (не забудьте проверить, что свойство изначально истинно).u2≤n<v2
И теперь, когда мы сделали все это, мы видим, что и : - квадратный корень из округленный до ближайшего целого числа.( u + 1 ) 2 > n u nu2≤n (u+1)2>n u n
источник