In che modo si ottiene l'invariante del ciclo in questo algoritmo di ricerca con limite di radice quadrata?


10

Originariamente su math.SE ma senza risposta lì.

Considera il seguente algoritmo.

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 

dove u, v e n sono numeri interi e l'operazione di divisione è divisione intera.

  • Spiega cosa viene calcolato dall'algoritmo.
  • Usando la tua risposta alla parte I come post-condizione per l'algoritmo, stabilisci un ciclo invariante e mostra che l'algoritmo termina ed è corretto.

In classe, la post-condizione è risultata essere e l'Invariante è . Non capisco davvero come sono state ottenute la post-condizione e gli invarianti. Immagino che la condizione del post fosse ... che chiaramente non è il caso. Quindi mi chiedo come sia stata ottenuta la post-condizione e l'invariante. Mi chiedo anche come ottenere la pre-condizione usando la post-condizione.0u2n<(u+1)20u2n<v2,u+1vu+1=v


Hai familiarità con la logica Hoare e ti aspetti che una risposta la tocchi?
Raffaello

Risposte:


8

Gilles ha ragione sul fatto che la tecnica generale è quella di andare a pescare per interessanti osservazioni.

In questo caso, potresti notare che il programma è un'istanza di ricerca binaria, perché ha la seguente forma:

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

Poi basta collegare il vostro particolare f, X... nella invariante generale per la ricerca binaria. Dijkstra ha una bella discussione sulla ricerca binaria .


7

u+1=v è in effetti una post-condizione del ciclo while (perché pensi che sia "chiaramente" non il caso?). Questo è sempre il caso di un ciclo while che non contiene un break: quando il ciclo termina, può essere solo perché la condizione del ciclo (qui, ) è falsa. Non è l'unica cosa che sarà vera quando il ciclo esce qui (questo algoritmo in realtà calcola qualcosa di interessante, come hai visto nella tua classe, quindi e sono anche post-condizioni), ma è il più ovvio.u+1vu=[this interesting thing]v=[this interesting thing]

Ora, per trovare altre proprietà interessanti, non esiste una ricetta generale. In effetti, esiste un certo senso formale in cui non esiste una ricetta generale per trovare invarianti a ciclo continuo. Il meglio che puoi fare è applicare alcune tecniche che funzionano solo in alcuni casi, o generalmente andare a pescare per osservazioni interessanti (che funziona sempre meglio man mano che diventi più esperto).

Se esegui il ciclo per alcune iterazioni con un valore di , vedrai che ad ogni iterazione:n

  • sia salti fino a ;u(u+v)/2
  • oppure passa a .v(u+v)/2

In particolare, inizia meno di e non lo supererà mai. Inoltre, inizia positivo e aumenta, mentre inizia da e diminuisce. Quindi è un invariante in tutto questo programma.v u v n + 1 0 u v n + 1uvuvn+10uvn+1

Una cosa che non è così ovvio è se può mai essere uguale a . Questo è importante: se e diventano mai uguali, avremo e il ciclo continuerà per sempre. Quindi è necessario dimostrare che e non diventano mai uguali al fine di dimostrare che l'algoritmo è corretto (ovvero che non esegue il loop per sempre). Una volta identificata questa necessità, è facile dimostrare (lo sto lasciando come esercizio) che è un invariante di loop (tieni presente che e sono numeri interi, quindi questo equivale a ).v u v x = u = v u v u < v u v u + 1 vuvuvx=u=vuvu<vuvu+1v

Poiché alla fine del programma, la post-condizione che ti è stata data può anche essere scritta (la parte è banale). Il motivo per cui vogliamo una post-condizione come questa, che coinvolga , è che vogliamo legare il risultato del programma con l'ingresso . Perché questa precisa condizione? Stiamo cercando qualcosa che sia il più preciso possibile e osserviamo dove appare all'interno del loop:v=u+1u2n<v20u2nnn

  • abbiamo ;uxv
  • quando , scegliamo il prossimo come , in modo che (e non cambi);x2nuxu2nv
  • quando , scegliamo la prossima come , in modo che (e non cambi).x2>nvxn<v2u

Questa dicotomia suggerisce che forse sempre. In altre parole, sospettiamo che sia un loop invariante. La verifica di ciò viene lasciata come esercizio al lettore (ricorda di verificare inizialmente che la proprietà sia vera).u2n<v2

E ora che abbiamo fatto tutto questo, vediamo che e : è la radice quadrata di arrotondata per difetto all'intero più vicino.( u + 1 ) 2 > n u nu2n(u+1)2>nun


"Quindi devi dimostrare che u e v diventano uguali per dimostrare che l'algoritmo è corretto" Penso che a questa frase manchi un "non".
sepp2k,

@KenLi Dato che questa è la tua domanda nel senso di Stack Exchange, c'è qualche miglioramento particolare che vorresti?
Gilles 'SO-smetti di essere malvagio' il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.