Как получить инвариант цикла в этом алгоритме поиска границ?


10

Первоначально по математике. Но там без ответа.

Рассмотрим следующий алгоритм.

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 в качестве пост-условия для алгоритма, установите инвариант цикла и покажите, что алгоритм завершается и корректен.

В классе было найдено, что равно а инвариант - . Я не очень понимаю, как были получены постусловие и инварианты. Я полагаю, что почтовое условие было ... что явно не так. Поэтому мне интересно, как был получен постусловие и инвариант. Мне также интересно, как предварительное условие может быть получено с помощью постусловия.0u2n<(u+1)20u2n<v2,u+1vu+1=v


Вы знакомы с логикой Хоара и ожидаете ли вы, что ответ коснется ее?
Рафаэль

Ответы:


8

Жиль прав, что основная техника - ловить рыбу для интересных наблюдений.

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

while i + 1 != k
  j := strictly_between(i, k)
  if f(j) <= X then i := j
  if f(j) > X then k := j

Затем вы просто подключаете свой конкретный f, X... в общий инвариант для бинарного поиска. У Дейкстры хорошее обсуждение бинарного поиска .


7

u+1=v действительно является постусловием цикла while (как вы думаете, почему это «явно» не так?). Это всегда имеет место в цикле while, который не содержит break: при выходе из цикла это может быть только потому, что условие цикла (здесь ) является ложным. Это не единственное, что будет верно, когда цикл выйдет отсюда (этот алгоритм фактически вычисляет что-то интересное, как вы видели в своем классе, так что и также являются постусловиями), но это наиболее очевидно.u+1vu=[this interesting thing]v=[this interesting thing]

Теперь, чтобы найти другие интересные свойства, нет общего рецепта. На самом деле, существует некоторый формальный смысл, в котором нет общего рецепта для поиска инвариантов цикла. Лучшее, что вы можете сделать, - это применить некоторые методы, которые работают только в некоторых случаях, или вообще ловить рыбу для интересных наблюдений (которые работают все лучше и лучше, когда вы становитесь более опытными).

Если вы запустите цикл для нескольких итераций с некоторым значением , вы увидите это на каждой итерации:n

  • либо подпрыгиваете до ;u(u+v)/2
  • или понижается до .v(u+v)/2

В частности, начинаете меньше, чем , и никогда не обгоните его. Кроме того, начинается с положительного значения и увеличивается, а начинается с и уменьшается. Таким образом, является инвариантом всей этой программы.uvuvn+10uvn+1

Одна вещь, которая не так очевидна, - может ли когда-либо быть равен . Это важно: если и когда-нибудь станут равными, у нас будет и цикл будет продолжаться вечно. Таким образом, вам нужно доказать, что и никогда не становятся равными, чтобы доказать, что алгоритм корректен (то есть не зацикливается вечно). Как только эта потребность была определена, легко доказать (я оставляю это как упражнение), что является инвариантом цикла (имейте в виду, что и являются целыми числами, так что это эквивалентно ).uvuvx=u=vuvu<vuvu+1v

Поскольку в конце программы, заданное вами постусловие также можно записать как (часть тривиальна). Причина, по которой нам нужно подобное пост-условие с участием , заключается в том, что мы хотим связать результат программы с входом . Почему это точное условие? Мы ищем что-то максимально точное и смотрим, где появляется внутри цикла:v=u+1u2n<v20u2nnn

  • у нас есть ;uxv
  • когда , мы выбираем следующий равным , так что (и не изменяется);x2nuxu2nv
  • когда , мы выбираем следующий равным , так что (и не меняется).x2>nvxn<v2u

Эта дихотомия намекает на то, что, возможно, все время. Другими словами, мы подозреваем, что это инвариант цикла. Проверка этого оставлена ​​читателю как упражнение (не забудьте проверить, что свойство изначально истинно).u2n<v2

И теперь, когда мы сделали все это, мы видим, что и : - квадратный корень из округленный до ближайшего целого числа.( u + 1 ) 2 > n u nu2n(u+1)2>nun


«Поэтому вам нужно доказать, что u и v становятся равными, чтобы доказать, что алгоритм верен». Я думаю, что в этом предложении отсутствует «не».
sepp2k

@KenLi Так как это ваш вопрос в смысле Stack Exchange, есть ли какие-то конкретные улучшения, которые вы хотели бы?
Жиль "ТАК - перестань быть злым"
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.