Corrigé TP 2

Suivant

On se propose d'écrire un programme qui calcule la somme de N entiers entre 0 et 20 La saisie des nombres et le calcul de la somme se feront dans une même boucle.

◊ Dans une première version du programme, N est demandé à l’utilisateur avant la saisie des valeurs

Solution Proposée :

Tout d'abord une petite analyse algorithmique. Comment calculer une somme ? Par exemple comment calculer : 

C'est à dire : 

L'algorithme consiste à effectuer les actions les unes après les autres. Ainsi pour calculer 1+2+3, on calcule 1+2, puis on ajoute 3 pour obtenir le résultat. 

De manière générale, on calcule x0 + x1, puis on ajoute x2, puis on ajoute x3, … puis on ajoute xn.

Il faut bien entendu conserver la valeur x0+x1 dans une variable pour pouvoir y ajouter x2. Afin de ne pas utiliser trop de mémoire, on conserve la même variable dans laquelle sont ajoutées au fur et à mesure les xk tout au long du calcul. Ce type de variable est appelée un accumulateur que nous notons S (comme somme). 

L'algorithme pour ajouter toutes les valeurs va donc consister en : S reçoit S + xk, et ce pour tous les xk à sommer. Cette structure algorithmique est celle d'une boucle, que nous pourrions écrire ainsi :

    pour tous les k allant de 0 à n

        S reçoit S + xk

Bien entendu, il faut d'abord prendre la précaution d'initialiser l'accumulateur sous peine d'avoir un résultat faux. Comme il s'agit d'une somme, on initialise S à zéro.

On peut traduire cet algorithme ainsi en langage C.

E2_1.c

Sens du symbole égal “=” :

Le signe égal peut avoir plusieurs significations ainsi ce symbole peut rendre une écriture ambigüe. Par exemple si l’on écrit : f(x) = 0, écrivons-nous une équation, c’est à dire que l’on cherche x tel que l’on ait la fonction f(x) nulle en ce x cherché, ou bien que l’on définit cette fonction f, nulle pour tout x ?

Dans le premier cas c’est un égal d’équation, dans le second un égal de définition.

En langage C, le signe égal ne doit pas se lire égal (bien qu’on le dise tous) mais il doit se dire «reçoit».

Si l’on écrit : x = x +1, il faut lire : x reçoit x+1.

Mais même avec cette lecture l’écriture est ambigüe. En effet comment x peut il être au même moment à gauche et à droite de l’affectation.

Il faut bien comprendre que l’impression d’instantanéité que nous avons avec nos machine n’est qu’un leure. Un ordinateur n’effectue qu’une opération à la fois, et le C effectue les opérations de la droite vers la gauche.

Par conséquent, l’affectation x = x +1 est effectuée en réalité en plusieurs étapes successives que l’on pourrait lister comme suit :

* évaluation de x + 1

* Stockage du résultat dans x.

Avec cette lecture le code devient compréhensible.

Analyse du programme : 

On procède d'abord à la saisie du nombre de valeurs à saisir.  Noter que si l'on entre N = 3, la boucle for ira de 0 à 2 inclus, ce qui fait bien trois valeurs. Par contre afin de ne pas afficher entrez la valeur 0, mais entrez la valeur 1, c'est i+1 qui est transmis au champ %d du printf.

Pour simplifier le programme, et comme il n'est pas demandé de conserver les valeurs lues au clavier, nous utilisons la même boucle pour faire la saisie et le calcul de la somme.

Noter la structure de la boucle for (syntaxe ici). Il y a trois zones dans une boucle for, et chaque zone est séparée des autres par un point virgule (d'où leur mise en gras et bleu dans le code ci-dessus), dans chaque zone, les différentes initialisations ou les différentes incrémentations sont séparées par des virgules

Nous profitons de cette possibilité pour initialiser dans la boucle for notre accumulateur appelé ici somme

Cette syntaxe n'est donnée ici que pour renforcer l'étude de la boucle for, elle n'est pas conseillée

Je vous conseille l'initialisation hors de la boucle for comme ceci par exemple :

    somme=0 ;
    for ( i=0  ; i<N ; i++ ) // 3 zones séparées par ;

Par contre, il est plus que fortement recommandé d'initialiser les accumulateurs juste avant leur boucle de sommation ! 

◊ Dans une seconde version du programme, la saisie des valeurs dure tant que l’on n’entre pas un code d’arrêt, ce code sera le nombre 99.

Cette fois-ci, on ne peut utiliser une boucle for pour la sommation, le nombre de valeurs à saisir et sommer n'est pas connu. Il faut donc utiliser une boucle conditionnelle : while ou do … while, leurs syntaxes sont ici : while, do…while. 

Solution avec do…while :

E2_2.c

Analyse du programme :

L'idée est d'effectuer la saisie et la somme tant que 99 n'a pas été saisi. 

Notez l'utilisation de l'opérateur combiné pour la somme.

Lors de l'affichage du résultat, comme nous sommes sur que 99 a été entré  (puisque l'on est sorti de la boucle do…while) la valeur affichée est diminuée de 99 pour ne pas fausser le calcul.

Le flux d'instructions reste dans la boucle do…while tant que la condition est vraie, comme le critère d'arrêt est la saisie de 99, on demande à rester dans la boucle tant que la valeur saisie est différente de 99 soit ici : x != 99 (soit x non égal à 99).

Enfin, il faut initialiser l'accumulateur somme avant la boucle.

Cette méthode a des avantages, on peut saisir autant de valeurs que l'on veut, pour peu qu'elle soit différente de 99...

Le même programme pourrait être fait avec une boucle while et non do…while, ce qui donnerait :

    somme  = 0 ;

    x = 1 ;

    while ( x != 99 )

    {   printf("Entrez une valeur : ");

        scanf("%d", &x  ) ;

        somme += x ; //somme = somme + x ;

    }

L'utilisation de la boucle while impose des modifications au programme :

1/ comme le test a lieu en début de boucle et non en fin de boucle, il faut initialiser la valeur de x pour être sur d'entrer une fois dans la boucle.

2/ Il ne faut pas de ; après le while alors qu'avec une boucle do…while, ce ; est requis.

◊ Prévoyez un test pour que x, la valeur saisie, reste dans les limites imposées 0 ≤ x ≤ 20, d'abord avec le programme du point 1, puis avec le programme du point 2.

Solution Proposée :

E2_3.c

Analyse du programme :

La seule différence avec le programme précédent est le test à l'aide de l'instruction if (syntaxe ici). Dans une première approche, on ne se contente de ne pas prendre en compte les saisies qui ne sont pas comprises entre 0 et 20 et qui ne sont pas 99.

Le test est complexe. On considère que la saisie est bonne si elle vaut 99 ou qu'elle est dans l'intervalle allant de 0 inclus à 20 inclus soit : ( x == 99) OU ( x dans l'intervalle [ 0 , 20 ] )

Dire que ( x dans l'intervalle [ 0 , 20 ] ) correspond à dire que "x supérieur ou égal à zéro et x inférieur ou égal à 20" soit (  ( x>=0 ) ET (x<=20 ) ).

Deux points sont à noter :

1/ comme il n'y a pas de priorité entre les opérateurs logiques (en fait tous sont au même niveau de priorité) il faut utiliser des parenthèses pour régler l'ordre des tests.

2/ Les opérateurs logiques sont  : OU : || (ALT+SHIFT+L sur un clavier Mac OS), et ET : &&. Ces opérateurs sont doublés. Les opérateurs non doublés existent mais ne sont pas au programme de cette unité.

Il est possible d'améliorer un peu le programme pour qu'il se comporte de façon plus efficace en informant l'utilisateur que la saisie est erronée : 

E2_4.c

En décomposant le test en cascade de tests, il est possible d'afficher un message approprié. De plus comme la somme n'est effectuée que si x est dans le bon intervalle, il n'est plus besoin de corriger la somme lors de l'affichage.

L3 EEA & ISS 2019-21 / p. castelan