Feuille d`exercices 2

publicité
Algorithmique
Feuille d’exercices 2: correction et terminaison des boucles
Prenons quelques tâches simples, pour lesquelles on demande d’écrire un algorithme qui la remplit, de
démontrer sa correction et, si nécessaire, sa terminaison. Ce sont plus des exercices de rédaction que de
réflexion. Les points à ne pas négliger :
— énoncer clairement les invariants de boucle
— justifier leur invariance
— vérifier qu’ils sont vrais avant la boucle pour en conclure qu’ils sont vrais après celle-ci.
Si on montre la terminaison avec un variant de boucle :
— indiquer clairement ce dernier en tant que variant de boucle
— au moins mentionner le fait qu’il ne prend que des valeurs entières, même si c’est évident
— justifier sa décroissance stricte d’une itération à la suivante
— justifier le fait qu’il ne peut pas décroı̂tre indéfiniment (qu’il doit rester positif, par exemple)
Les deux premiers exercices sont corrigés pour donner un exemple du niveau de formalisme attendu.
1. pgcd de a et b : On choisit l’algorithme d’Euclide, avec une précaution au début pour s’assurer de la
positivité des arguments :
a=abs(a)
b=abs(b)
while b>0:
r=a%b
a=b
b=r
d=a
Correction : On note a0 et b0 les valeurs initiales de a et b. La positivité de a et b, le fait que pgcd(a,
b)=pgcd(a0 , b0 ), sont des invariants de la boucle :
— si b est positif avant une itération, a qui prend sa valeur au cours de cette itération sera positif après
cela. La valeur de b après une itération est le reste de la division euclidienne de deux naturels :
elle est donc positive.
— en notant ai et bi les valeurs de a et b avant une itération, et af et bf leurs valeurs après cette
itération, on a af = bi et ai = q × bi + bf pour un certain entier q. Comme ai et bi sont des
combinaisons entières de af et bf , et réciproquement af et bf sont des combinaisons entières de
ai et bi , on a pgcd(ai , bi )=pgcd(af , bf )
Ces invariants étant vrais avant l’entrée dans la boucle, ils le sont encore à sa sortie. D’après la
condition de sortie de boucle, on a b= 0 à ce moment-là, ce qui permet de conclure que a, et donc d,
vaut pgcd(a0 , b0 ).
Terminaison : b est un variant de boucle : il est évidemment à valeurs entières, et à chaque itération,
sa valeur finale bf est le reste dans une division euclidienne par sa valeur initiale, bi : on a donc
0 ≤ bf < bi et par conséquent b décroı̂t strictement à chaque itération. Comme il doit rester positif
d’après la condition de la boucle, ceci prouve la terminaison de cette boucle.
2. Écrire un algorithme qui prend une liste t et une valeur x, et détermine si x est un élément de t.
Réponse :
1
def contient(L,x):
n=len(L)
present=False
for i in range(n):
if L[i]==x:
present=True
return present
Correction :
— Montrons que la formule I : “present ⇔ ∃j < i tel que x = L[j]” est un invariant de cette boucle.
— Si elle est vraie au début d’une itération, à la fin de celle-ci on est dans l’un des deux cas suivants :
soit L[i]=x et present=True, soit L[i]6=x et present est inchangé, c’est à dire present ⇔ ∃j < i
tel que x = L[j]. Dans les deux cas, cela signifie que present ⇔ ∃j < (i + 1) tel que x = L[j], et
donc qu’après incrémentation de i, l’invariant est toujours vrai au début de l’itération suivante.
— Comme I est évidemment vrai au début de la boucle quand i=0 et present=False, on en déduit
qu’il est vrai à la fin de la boucle en imaginant i=n.
— Il en découle que la valeur booléenne retournée est équivalente à “∃j < n tel que x = L[j]”,
autrement dit au fait que x soit un élément de L.
3. Pareil avec un algorithme de calcul du minimum d’une liste. (Donné en exemple dans le chapitre
“Complexité”)
4. Pareil avec un algorithme calculant la somme des éléments d’une liste.
5. Décomposition en base b ≥ 2. On rappelle que l’écriture en base b c1 c2 . . . cn représente l’entier
b
n
X
ci bn−i . On considère la fonction suivante, tirée d’un énoncé de CCP 2015 :
i=1
def chiffres(n,b):
""" Donnees : deux entiers n>0 et b>1
Resultat : une liste de chiffres"""
t=[]
while n>0:
c=n%b
t.append(c)
n=n//b
return t
(a) Cette fonction calcule l’écriture en base b≥ 2 de l’entier n. Formaliser cette spécification par une
précondition et une postcondition.
(b) Justifier la terminaison de la boucle while (ce que l’énoncé de 2015 demandait). Quelle partie de
la précondition est nécessaire pour cela ?
(c) Démontrer à l’aide d’un invariant de boucle que l’algorithme satisfait cette spécification.
6. Donner un algorithme prenant deux listes de même longueur, et retournant leur produit scalaire.
Prouver sa correction.
7. Pareil avec un algorithme qui compte le nombre d’éléments nuls dans une liste L reçue en argument.
len(t)−1
X
Indice pour la question 5c : utiliser l’invariant “n ∗ blen(t) +
bi t[i] est égal au n initial”.
i=0
8. Écrire en python un algorithme de recherche par dichotomie qui prend une liste t triée dont on sait
qu’elle contient x, et détermine l’indice de x dans cette liste. Prouver sa correction et sa terminaison.
2
Téléchargement