• Aucun résultat trouvé

Conversion binaire-d´ ecimal

En se basant sur les principes discut´es dans la section 2.1, on souhaite effectuer deux op´erations.

1. Lire un nombre de type int et imprimer sa repr´esentation binaire (aussi de type int). Par exemple :

On lit On imprime

19 10011

2. Lire un nombre de type int dont les chiffres varient dans {0, 1}, le voir comme un nombre binaire et imprimer sa repr´esentation d´ecimale (aussi de type int). Par exemple :

On lit On imprime

10011 19

Le lecteur remarquera que dans cet exemple on utilise un sous-ensemble des valeurs de type int (celles dont les chiffres varient sur 0 et 1) pour repr´esenter les nombres binaires.

Dans une mise en oeuvre il est naturel d’introduire une fonction pour chaque conver-sion. Remarquons que la solution ci-dessous utilise la fonction de biblioth`eque assert de la biblioth`eque assert.h. La commande assert(b) ´evalue la condition logique b. Si la condition est fausse le calcul s’arrˆete et un message d’erreur est ´emis qui permet d’identifier l’assertion qui n’est pas valide. Avec la fonction assert, on a une fa¸con simple et fort utile de documenter et tester un programme. 1 int d e c _ t o _ b i n (int d ){ 2 int q , r ; 3 if ( d = = 0 ) { 4 r e t u r n 0;} 5 e l s e{ 6 r = d %2; 7 q = d /2; 8 r e t u r n ( r + 1 0 * d e c _ t o _ b i n ( q ) ) ; } } 9 int b i n _ t o _ d e c (int b ){ 10 int q , r ; 11 if ( b = = 0 ) { 12 r e t u r n 0;} 13 e l s e{ 14 r = b % 1 0 ; 15 q = b / 1 0 ; 16 a s s e r t (( r = = 0 ) || ( r = = 1 ) ) ; 17 r e t u r n ( r +2* b i n _ t o _ d e c ( q ) ) ; } } 18 int m a i n(){ 19 p r i n t f(" E n t r e z 10 p o u r d ´e c i m a l et 2 p o u r b i n a i r e \ n "); 20 int c h o i x ; 21 int x ; 22 s c a n f("% d " ,& c h o i x ); 23 a s s e r t (( c h o i x = = 2 ) | | ( c h o i x = = 1 0 ) ) ; 24 if ( c h o i x = = 1 0 ) { 25 p r i n t f(" E n t r e z un n o m b r e d ´e c i m a l e \ n " ) ; } 26 e l s e{ 27 p r i n t f(" E n t r e z un n o m b r e b i n a i r e \ n " ) ; } 28 s c a n f("% d " ,& x ); 29 if ( c h o i x = = 1 0 ) { 30 p r i n t f("% d \ n " , d e c _ t o _ b i n ( x ) ) ; } 31 e l s e{

Fonctions 41

32 p r i n t f("% d \ n " , b i n _ t o _ d e c ( x ) ) ; }

Chapitre 5

Fonctions r´ecursives

Un programme C est compos´e d’une liste de fonctions qui peuvent s’appeler mutuellement. En particulier, une fonction peut s’appeler elle mˆeme ; il s’agit alors d’un exemple de fonction r´ecursive (n fonctions qui s’appellent mutuellement sont aussi des fonctions r´ecursives). On a d´ej`a examin´e dans l’exemple 4 la programmation de l’algorithme d’Euclide par une fonction r´ecursive. Les fonctions r´ecursives permettent de programmer ais´ement les d´efinitions par r´ecurrence qu’on trouve souvent en math´ematiques. Aussi, un certain nombre d’algorithmes qui suivent une strat´egie diviser pour r´egner se programment naturellement de fa¸con r´ecursive ; par exemple, la recherche dichotomique et certains algorithmes de tri qu’on ´etudiera dans la section 7.1 suivent cette strat´egie. On a vu dans l’exemple 12 que l’algorithme d’Euclide peut se programmer aussi avec une boucle ; on dira aussi de fa¸con it´erative. La r´ecursion utilis´ee dans la programmation de l’algorithme d’Euclide est de type terminal dans le sens qu’apr`es l’appel r´ecursif il ne reste plus rien `a faire et la fonction retourne imm´ediatement.1Il se trouve que pour la r´ecursion terminale (tail recursion en anglais), un compilateur optimisant peut g´en´erer automatiquement un programme it´eratif ´equivalent.

Dans la section 5.1, on pratique la programmation r´ecursive et it´erative dans le cadre du probl`eme de l’´evaluation de polynˆomes.

Comme on l’a vu dans la section 1.2, l’appel et le retour de fonction manipule implicitement une pile de blocs d’activation. Il s’av`ere que dans certaines situations cette structure de donn´ees permet une programmation ´el´egante et compacte. Dans la section 5.2, on illustre une telle situation avec le probl`eme de la tour d’Hano¨ı.

Enfin, il y a aussi des situations dans lesquelles la programmation d’une d´efinition par r´ecurrence `a l’aide d’une fonction r´ecursive peut g´en´erer un programme particuli`erement inefficace. Dans la section 5.3, on examine diff´erentes strat´egies pour contourner ce probl`eme dans le contexte du calcul de la suite de Fibonacci.

5.1 Evaluation de polynˆ´ omes

Consid´erons le probl`eme de l’´evaluation d’un polynˆome de degr´e n : p(x) = a0+ a1x + · · · + anxn

dans un point x. Un premier algorithme peut consister `a calculer les sommes partielles : a0, a0+ a1x, a0+ a1x + a2x2, · · ·

1. Il s’agit d’une intuition, on ne donnera pas de d´efinition formelle de la r´ecursion terminale.

en calculant en parall`ele les puissances de x :

x0, x1 = x · x0, x2 = x · x, x3 = x · x2, . . .

Pour ce calcul, il faut donc effectuer 2 · n − 1 multiplications ainsi que n sommes. Cependant le coˆut d’une somme est bien inf´erieur `a celui d’une multiplication et donc on peut consid´erer que le coˆut du calcul d´epend essentiellement du nombre de multiplications.

R`egle de Horner

La r`egle de Horner est un autre algorithme pour ´evaluer un polynˆome de degr´e n dans un point qui demande seulement n multiplications. On d´efinit :

h0 = an

hi = hi−1x + an−i 1 ≤ i ≤ n . On remarque que :

hi = anxi+ an−1xi−1+ · · · + an−i+1x + an−i . Donc p(x) = hnet on peut calculer p(x) avec seulement n multiplications !

Exemple 19 Pour mettre en oeuvre l’´evaluation d’un polynˆome on va faire l’hypoth`ese que le programme lit le degr´e du polynˆome, un point o`u il faut ´evaluer le polynˆome et les coefficients du polynˆome. Pour l’instant, on ne dispose pas d’une structure de donn´ees pour m´emoriser (de fa¸con simple) n + 1 coefficients o`u n est variable ; les tableaux qui seront discut´es dans le chapitre 6 feront l’affaire. Il s’agit donc de lire les coefficients et en mˆeme temps de faire progresser l’´evaluation du polynˆome.2 Pour mettre en oeuvre l’algorithme on a 4 choix pos-sibles. En effet, on peut choisir entre la m´ethode d’´evaluation directe et la m´ethode de Horner et aussi entre une programmation par r´ecursion et une par it´eration. On pr´esente ci-dessous la m´ethode de Horner programm´ee de fa¸con r´ecursive et it´erative et on laisse en exercice le mˆeme probl`eme pour la m´ethode directe. Notez que dans la version r´ecursive on lit les coef-ficients dans l’ordre a0, a1, . . . , an alors que dans la version it´erative on proc`ede dans l’ordre inverse. 1 d o u b l e h o r n e r _ r e c (int i , d o u b l e x , int n ){ 2 d o u b l e a ; 3 p r i n t f(" E n t r e z c o e f f i c i e n t % d \ n " , i ); 4 s c a n f("% lf " ,& a ); 5 if ( i == n ){ 6 r e t u r n a ;} 7 e l s e{ 8 r e t u r n ( a + x * h o r n e r _ r e c ( i +1 , x , n ) ) ; } } 9 d o u b l e h o r n e r _ i t (d o u b l e x , int n ){ 10 d o u b l e a ; 11 d o u b l e b ; 12 p r i n t f(" E n t r e z c o e f f i c i e n t % d \ n " , n );

2. On voit ici un exemple d’algorithme en ligne (on line en anglais) dans lequel le programme ne dispose pas d’assez de m´emoire ou de temps pour m´emoriser toutes les entr´ees avant de commencer le calcul. Typiquement, on trouve ce type d’algorithme dans des situations o`u il faut traiter des grandes masses de donn´ees et/ou le processeur qui traite ces donn´ees a un pouvoir de calcul limit´e.

Fonctions r´ecursives 45 13 s c a n f("% lf " ,& a ); 14 int i ; 15 for ( i =1; i <= n ; i = i + 1 ) { 16 p r i n t f(" E n t r e z c o e f f i c i e n t % d \ n " ,( n - i )); 17 s c a n f("% lf " ,& b ); 18 a = b + x * a ;} 19 r e t u r n a ;}