• Aucun résultat trouvé

La correction de l algorithme dépend de la façon dont sont gérés les nombres, notamment les nombres réels. k si n > 0 et 0 si n = 0.

N/A
N/A
Protected

Academic year: 2022

Partager "La correction de l algorithme dépend de la façon dont sont gérés les nombres, notamment les nombres réels. k si n > 0 et 0 si n = 0."

Copied!
6
0
0

Texte intégral

(1)

1 Calcul de la moyenne de deux nombres

1.1 Sp´ ecifications du probl` eme

L’objet initial : deux nombresaetb

Le r´esultat attendu : un nombre ´egal `a (a+b)/2

1.2 code

1 def moyenne(a, b):

2 return (a + b) / 2

1.3 Terminaison

Aucun probl`eme en vue : une seule instruction avec unsimple calcul.

1.4 Correction partielle

Aucun probl`eme en vue : le calcul correspondexactement `a la formule

1.5 Correction totale

L’algorithme termine et il est partiellement correct donc l’algorithme est correct.

1.6 Remarques

La correction de l’algorithme d´epend de la fa¸con dont sont g´er´es les nombres, notamment les nombres r´eels.

2 Somme des n premiers entiers

2.1 Sp´ ecifications du probl` eme

L’objet initial : un nombre entiernpositif ou nul Le r´esultat attendu : un nombre entier ´egal `a Pn−1

k=0k sin >0 et 0 sin= 0.

2.2 Code

1 def somme(n):

2 S = 0

3 for i in range(n):

4 S += i

5 return S

2.3 Terminaison

— Il y a une boucle formais le nombre de passages dans la boucle est connu a priori (c’estn).

— L’algorithme se termine toujours (apr`esnex´ecutions de la boucle).

Plus formellement,iest un variant de la boucle qui est contraint par l’instruction in range(n) de prendre successivement les valeurs : 0,1, . . . , n−1.

L’algorithme termine pour le cas limiten= 0. Dans ce cas in range(n) renvoie la liste vide ([], et la boucle n’est pas pas ex´ecut´ee.

2.4 Correction partielle

Comme on retourne S, on v´erifie que S contient `a la fin de l’ex´ecution le r´esultat attendu, c’est-`a-dire la somme des n premiers entiers :

— on v´erifie que l’initialisation deS est correcte ;

— on v´erifie que les modifications deS dans la boucle sont correctes ;

— on v´erifie que le nombre d’it´erations est correct ;

(2)

alors l’algorithme est correct.

Plus formellement, l’invariant de la boucle est la propri´et´e ”S est ´egale `a la somme des i premiers entiers positifs” : P(S=Pi

k=0k). Soit la suiteSinit =Si−1, S0, . . . , Sn−1 des valeurs successives de la variableS;

— initialement (avant d’entrer dans la boucle), la propri´et´eP est v´erifi´ee, la somme des 0 premiers entiers positifs est

´egale `a 0 (Sinit=Si−1= 0) ;

— D’une it´eration sur l’autre de la boucle,P est conserv´ee :Si=i+Si−1=i+Pi−1

k=0k=Pi k=0k)) ;

— A la fin de la boucle, la propri´et´eP est v´erifi´ee eti=n−1, doncSf inal=Sn−1=Pn−1 k=0k.

2.5 Correction totale

— Sin= 0, l’algorithme termine et renvoie 0

— Sin >0, l’algorithme termine et renvoiePn−1 k=0k

2.6 Remarques

Sinest contraint en pr´e-condition `a ˆetre strictement sup´erieur `a 0, on n’a pas `a g´erer le cas d´eg´en´er´en= 0.

Si on voulait calculer la somme des n premiers entiers strictement positifs (Pn−1

k=1k, si n > 0 et 0 si n = 0, il faudrait modifier la boucle : for i in range(1,n+1). La d´emonstration est sensiblement identique, avec des sommes qui d´emarrent

` a 1.

3 Le Zune date bug

3.1 Sp´ ecifications du probl` eme

L’objet initial : un nombre entier j positif ou nul qui est le nombre de jours depuis le premier janvier 1980 et le jour courant.

Le r´esultat attendu : un couple de nombres entiers positifs ´egal `a (j, a) qui est le nombre de jours depuis le premier janvier de l’ann´ee courante et le jour courant.

3.2 Code

1 def jour_de_l_annee(jour, annee=1980):

2 while jour > 365:

3 if bissextile(annee):

4 if jour > 366:

5 jour -= 366

6 annee += 1

7 else:

8 jour -= 365

9 annee += 1

10 return (annee, jour)

3.3 Terminaison

Soitjk et ak les suites des valeurs prises respectivement par la variable jour et par la variable annee. Les instructions de la boucle permettent de dire que si bissextile(ak) est vrai et si jk > 366 alors jk+1 = jk−366 et si bissextile(ak) est faux (else de if bissextile(annee)) alors jk+1 =jk −365. Il existe une valeur de ak et jk telle que jk >365 et bissextile(ak)estvrai et jk <= 366. Par exemple :ak = 1980 et jk = 366. Dans ce casjk+1 =jk et ak+1 =ak. Donc jk ne peut ˆetre pris comme variant de la boucle.

Pour que l’algorithme termine, deux solutions peuvent envisag´ee :

— Sortir les cas probl´ematiques de la pr´e-condition. C’est ce que fait Microsoft en conseillant de ne pas allumer l’appareil les 31 d´ecembre des ann´ees biessextiles. Il est en effet possible de montrer que la valeur qui met en d´efaut la terminaison ne peut survenir que lorsque le jour correspond au 31 d´ecembre d’une ann´ee biessextilebissextile(ak) est vrai etjk<= 366).

— Capturer la valeur probl´ematique dans la condition de la boucle while :

1 def jour_de_l_annee(jour, annee=1980):

2 while (not bissextile(annee) and jour > 365)

3 or (bissextile(annee) and jour > 366):

4 if bissextile(annee):

(3)

6 jour -= 366

7 annee += 1

8 else:

9 jour -= 365

10 annee += 1

11 return (annee, jour)

Dans ce cas, la terminaison est garantie ´egalement pour les valeurs qui v´erifientjk= 365 etbissextile(ak) est vrai.

Il est ´egalement possible d’effectuer unbreak`a l’int´erieur de la boucle :

1 def jour_de_l_annee(jour, annee=1980):

2 while jour > 365 :

3 if bissextile(annee):

4 if jour > 366:

5 jour -= 366

6 annee += 1

7 else :

8 break

9 else:

10 jour -= 365

11 annee += 1

12 return (annee, jour)

Souvent d´ecri´ee, parce que la preuve de l’algorithme est plus compliqu´ee (il faut d´emontrer que le cas probl´ematique est bien captur´e par leelse) et parce que le code est moins lisible (plus difficile de voir les sorties de boucle), cette solution (suvent qualifi´ee de paresse algorithmique) a l’avantage d’ˆetre rapide `a mettre en place et ´evite de faire des erreurs dans la d´efinition de la condition d’arrˆet.

3.4 Correction partielle

La difficult´e ici est que le r´esultat attendu n’est pas caract´eris´e math´ematiquement. Il faut montrer que la valeur de retour de l’algorithme correspond `a l’ann´ee et au jour courant, en prenant en compte les ann´ees bissextiles.

Soit la propri´et´e :P0= (j0=jk+ (ak−a0)×365 +nbk), avecjk,ak, les valeurs dejouretanneeapr`eskpassages dans la boucle,j0 et a0, les valeurs initiales de de jouret annee, etnbk le nombre d’ann´ees bissextiles apr`esk passages dans la boucle.jk est le nombre de jours entre le premier janvier de l’ann´eeak et le jour courant.

La propri´et´eP0 est v´erifi´ee (tautologiej0=j0). Que se passe-t-il entre l’it´erationket l’it´erationk+ 1 ?

— Si bissextile(annee) et jour > 366 sont vrais,ak+1=ak+ 1,jk+1=jk−366, etnbk+1=nbk+ 1. Donc :

jk+1+ (ak+1−a0)×365 +nbk+1= jk−366 + (ak+ 1−a0)×365 +nbk+ 1 = jk+ (ak−a0)×365 +nbk=j0

Pk+1 est donc toujours v´erifi´ee.

— Si bissextile(annee) est faux (et jour > 365 est vrai, sinon la boucle est termin´ee),ak+1=ak+1,jk+1=jk−365, etnk+1=nk. Donc :

jk+1+ (ak+1−a0)×365 +nbk+1= jk−365 + (ak+ 1−a0)×365 +nk= jk+ (ak−a0)×365 +nbk=j0

Pk+1 est donc toujours v´erifi´ee.

— Dans les autres cas,ak+1=ak,jk+1=jk, etnk+1=nk, Pk+1 est donc toujours v´erifi´ee.

Si la boucle termine, on a bien (j0=jpost+ (apost−a0)×365 +nbpost), avec apost, le nombre d’ann´ees depuis 1980 et jpost≤366, si la derni`ere ann´ee est bissextile etjpost≤365 sinon.

3.5 Correction totale

Le code corrig´e est correct, il termine avec les bonnes valeurs deanneeetjour.

4 Un exemple : le calcul du PGCD par la m´ ethode d’Euclide

4.1 Code

(4)

1 def euclide(a, b):

2 while b != 0:

3 a, b = b, a % b

4 return a

4.2 Terminaison

La variable b est un variant de la boucle. En effet, bk+1 = akmodbk et donc par d´efinition du modulo bk+1 < bk et bk+1>= 0.

4.3 Correction partielle

Soitak et bk la valeur des variables aet bapr`esk passages dans la boucle. La propri´et´ePk :pgcd(a0, b0) =pgcd(ak, bk) est un invariant de la boucle :

— Elle est trivialement v´erifi´ee pourk= 0

— pgcd(ak+1, bk+1) =pgcd(bk, akmodbk) =pgcd(ak, bk). SiPk est verifi´ee,pgcd(ak+1, bk+1) =pgcd(a0, b0), doncPk+1 est v´erifi´ee.

— `a la derni`ere it´eration,bk = 0 (condition de sortie de la boucle), etpgcd(a0, b0) =pgcd(ak, bk) =pgcd(ak,0) =ak.

4.4 Correction totale

L’algorithme termine et renvoie bien la valeur dupgcd deaet deb.

5 Exponentiation It´ erative avec une boucle for

5.1 Code

1 def expo_ite_naive(x,n):

2 p = 1

3 for i in range(n):

4 p *= x

5 return p

5.2 Terminaison

i est un variant de la boucle qui est contraint par l’instruction in range(n) de prendre successivement les valeurs : 0,1, . . . , n−1.

L’algorithme termine pour le cas limiten= 0. Dans ce cas in range(n) renvoie la liste vide ([], et la boucle n’est pas pas ex´ecut´ee.

5.3 Correction partielle

L’invariant de la boucle est :pk =xk.

— Il est v´erifi´e avant d’entrer dans la boucle (k= 0 etp0= 1 =x0).

— il est conserv´e de l’it´erationk `a l’it´erationk+ 1 :pk+1=x×pk =x×xk =xk+1.

— Il est v´erifi´e apr`es la l’it´erationk=n(ivariant de 0 `an−1, il y a nit´erations), doncpn =xn.

6 Exponentiation rapide avec une boucle while

1 def expo_ite_rapide(x,n):

2 m = n

3 res = 1

4 puiss = x

5 while m != 0:

6 if m % 2 == 1:

7 res = res * puiss

8 m = m // 2

9 puiss = puiss ** 2 return res

(5)

6.1 Terminaison

Comme d’une it´eration sur l’autre,mk+1=bmk/2c< mk, simk+1>0. Donc la suitemk atteint 0.

6.2 Correction partielle

Un invariant de la boucle est :xn =res×puissm:

— C’est vrai avant la boucle :res×puissm= 1×xn =x.

— La propri´et´e est conserv´ee d’une it´erationk`a une it´erationk+ 1 :

— Simk est pair, il peut s’´ecriremk= 2a, mk+1=a, et :

resk+1×(puissk+1)mk+1 = resk×((puissk)2)a= resk×(puissk)2a= resk×(puissk)mk =xn

— Simk est pair, il peut s’´ecriremk= 2a+ 1,mk+1=a, et :

resk+1×(puissk+1)mk+1= resk×puissk×((puissk)2)a = resk×puissk×(puissk)2a= resk×(puissk)2a+1= resk×(puissk)mk=xn

7 Recherche dichotomique dans un tableau tri´ e

1 def dichotomie(t, v):

2 a = 0

3 b = len(t) - 1

4 while a <= b:

5 m = (a + b) // 2

6 if t[m] == v:

7 # on a trouv´e v

8 return True

9 elif t[m] < v:

10 a = m + 1

11 else:

12 b = m - 1

13 # on a a > b

14 return False

8 Tri par insertion

1 def tri_insertion(T):

2 for index in range(len(T)):

3 item = T[index]

4 j = index

5 while j>0 and liste[j-1] > item:

6 liste[j] = liste[j-1]

7 j=j-1

8 liste[j]=item

9 Vote ` a la majorit´ e na¨ıf

1 def vote_majorite(t):

2 for x in t:

3 c = 0

4 for y in t:

5 if x == y :

(6)

6 c = c +1

7 if c > len(t) // 2 :

8 return x

9 return None

10 Vote ` a la majorit´ e (Boyer-Moore)

1 def vote_majorite_BM(t):

2 m = 0

3 i = 0

4 for x in t:

5 if i == 0 :

6 m = x

7 i = 1

8 elif m == x :

9 i = i + 1

10 else :

11 i = i -1

12 return m

11 Multiplication russe

1 def mult(m, n):

2 r = 0

3 while n > 0:

4 if n%2 == 1:

5 r += m

6 m *= 2

7 n //= 2

8 return r

12 Recherche du maximum par dichotomie

1 def maxdic(tab, beg, end):

2 if beg + 1 < end:

3 mid = (beg + end) // 2

4 maxl = maxdic(tab, beg, mid)

5 maxr = maxdic(tab, mid, end)

6 if maxl > maxr:

7 return maxl

8 else:

9 return maxr

10 else:

11 return tab[beg]

12

13 def maxtab(tab):

14 return maxdic(tab, 0, len(tab))

Références

Documents relatifs

On déduit de la

6- Dessine une fléchette de la même couleur sur les ballons du

4- Range les nombres du plus petit au

3- Range les nombres du plus petit au

cent trente-huit cent soixante-treize cent quatre-vingts cent

trois cent quarante et un deux cent cinq cent soixante-dix-neuf quatre cent

3- Utilise les étiquettes pour former le plus de nombres possibles contenant le mot « cent ». 4- Range les nombres du plus petit au

Comment peut-on calculer facilement une approximation de ln 3 avec deux chiffres exacts apr` es la virgule?.