programmation en C / LabWindows 1 le langage

Transcription

programmation en C / LabWindows 1 le langage
informatique - S1
programmation en C / LabWindows
1 le langage C/LabWindows
Un programme informatique est, en toute généralité, une suite d’instructions intermédiaires entre le langage courant (les mots et phrases de tous
les jours permettant de décrire un algorithme, une « marche à suivre ») et le
langage machine (une suite de 0 et de 1).
Des milliers de langages de programmation existent, généralistes
(comme le C, le Pascal, . . .) ou spécialisés (par exemple maple pour le calcul
formel, php pour la programmation de sites web dynamiques, perl pour les
manipulations d’expressions, R pour les statistiques, . . .)
LabWindows propose un environnement complet de programmation en
langage C, l’un des plus répandus.
2 variables
Une variable est une « case mémoire » permettant de stocker une donnée
(un entier, un réel, un caractère, . . .).
Le langage impose, avant utilisation, de déclarer les variables, c’est-àdire de préciser son nom et le type de données qu’elle pourra contenir.
Il est de plus fortement conseillé d’initialiser chaque variable avant
usage, c’est-à-dire de lui affecter une valeur initiale. En effet, une variable
déclarée mais non initialisée aura une valeur aléatoire, dépendant de l’état
de la mémoire de l’ordinateur, ce qui peut créer lors de l’éxécution des dysfonctionnements difficiles à détecter et à corriger.
exemple 1 :
int i;
i=2;
déclare une variable entière nommée i puis lui affecte la valeur 2. On
peut aussi effectuer ces deux opérations en une seule instruction :
int i=2;
département Mesures Physiques - IUT1 - Grenoble
Le nom de la variable doit commencer par une lettre, et peut ensuite être
composé librement de lettres, de chiffres et du tiret de soulignement _.
Le C distingue lettres majuscules et minuscules : A et a sont deux variables distinctes. De plus, on ne peut définir en C deux variables de types
différents ayant le même nom : les déclarations int a; double a; ne
peuvent se suivre.
Les principaux types de variables sont :
— les entiers, déclarés par int,
ce sont des entiers signés codés sur 4 octets soit 32 bits. Ils sont donc
compris entre −231 = −2 147 483 648 et 231 − 1 = +2 147 483 647.
— les réels simple précision déclarés par float,
ce sont des nombres à virgule codés sur 4 octets, donc compris entre
-3.4e38 et +3.4e38.
exemple :
float pi=3.1415927;
Compte-tenu de la puissance et de la mémoire des ordinateurs dont
vous disposez, utiliser les réels simple précision ne comporte plus
grand intérêt par rapport aux réels double-précision.
— les réels double-précision, déclarés par double,
ce sont des nombres à virgule codés sur au moins 8 octets, pour représenter des nombres compris entre -1.7e308 et +1.7e308 au moins.
exemple :
exemple :
double pi=3.14159265358979;
double x=1.265443929243e+222;
— les caractères, déclarés par char,
permettant de coder l’un des 256 caractères alphanumériques de la
table des codes ASCII, codés sur un octet.
exemple :
char c=’a’;
4 affichage
— les chaînes de caractères, déclarées par char nomvariable[n]
où n est un entier qui représente le nombre maximal de caractères
dans la chaîne.
exemple :
char c[30];
déclare une chaîne nommée c et pouvant contenir au plus 30 caractères. Il est cependant difficile de lui affecter directement une valeur
dans le corps du programme : nous verrons plus loin comment l’utilisateur pourra saisir au clavier une chaîne.
4.1
la fonction printf
Pour afficher le contenu d’une variable, on utilise la fonction printf
qui réalise un affichage formaté, en permettant de mélanger texte et contenu
de variables.
exemple :
printf("message");
affiche simplement le texte message
remarque : une chaîne de caractère est en fait un tableau de caractères, de construction analogue aux tableaux de nombres que l’on décrira plus loin (voir 10).
Une chaîne de caractères explicite est écrite, dans un printf, en indiquant les caractères entre ", pour la distinger d’un nom de variable.
Si l’on souhaite afficher le contenu d’une variable, il faut préciser son
type dans la chaîne de formatage, et ensuite indiquer son nom :
exemple :
printf("%d",message);
affiche le contenu de la variable entière message (sous réserve qu’elle
ait été déclarée préalablement bien sûr).
3 constantes
4.2 différents types d’affichage
Si un programme utilise plusieurs fois une valeur approchée du nombre
π, on peut pour éviter de re-taper cette valeur, définir une variable réelle par
l’instruction double pi=3.1415926;.
On peut bien entendu mélanger texte et contenu de variables, en donnant
une chaîne de caractère composée des caractères à afficher et de symboles
spéciaux débutant par % qui indiquent la place et le type des variables. Ainsi :
%d indique un entier écrit en base 10 (décimal), %x indique un entier
écrit en base 16 (hexadécimal),
%f indique un réel (float),
%e indique un réel en écriture scientifique (avec un exposant),
%lf indique un réel double-précision (long float),
%le indique un réel double-précision en écriture scientifique,
%c indique un caractère (char),
%s indique une chaîne de caractères (string).
Mais la valeur de la variable ne changeant pas tout au long de l’exécution
du programme, utiliser une variable n’est pas le meilleur choix : on préfèrera
utiliser une constante.
Il s’agit d’un simple raccourci : un
#define PI 3.1415926
placé en tout début de programme, et qui indique au compilateur de remplacer chaque occurrence de PI dans le code-source par la valeur associée
3.1415926. Ainsi, dans le programme compilé, aucune variable inutile
n’apparaît, ce qui assure un (petit) gain de place mémoire et de temps d’exécution. Cela ajoute aussi de la lisibilité au code.
exemple :
main()
{
int i=2;
double x=2.256;
Attention à la syntaxe : pas de signe =, pas de ; à la fin de la ligne
#define PI 3.1415926, qui n’est pas à proprement parler une instruction mais une directive de compilation appelée macro.
2
char c=’a’;
4.4 caractères spéciaux
printf("entier %d, réel %lf, caractère %c",i,x,c);
}
Outre ces symboles précédés de % qui permettent d’afficher le contenu
des variables, on note aussi l’existence de certains "caractères spéciaux",
précédés d’un « backslash » : \n qui insère un saut de ligne, \s qui insère
une espace, \t qui insère une tabulation.
affiche le texte : entier 2, réel 2.256, caractère a.
Les caractères \ et % n’apparaissent donc pas à l’écran à l’exécution du
programme : si l’on désire réellement les afficher, il faut les doubler :
printf("\\") affichera \ et printf("%%") affichera %.
4.3 affichage des réels
Les différentes formes d’affichage de réels (%f, %e, %lf, %le) permettent, en option, de préciser à la fois le nombre total de caractères à afficher et le nombre de chiffres après la virgule.
Notons enfin la fonction Cls() (spécifique à LabWindows) qui efface
le contenu de la fenêtre d’affichage.
On indique ces nombres, séparés par un point, juste après le % :
exemple : le programme
5 saisie de valeurs au clavier : scanf
main()
{
double pi=3.14159265358979;
double x=3009444.34;
La fonction scanf est symétrique de la fonction printf : elle permet
de saisir au clavier une valeur à ranger dans une variable.
exemples :
scanf("%d",&i); range dans la variable i un entier saisi au clavier.
scanf("%lf",&x); range dans la variable x un réel saisi au clavier.
scanf("%c",&c); range dans la variable c un caractère.
Cls();
printf("%6.2lf", pi);
printf("\n%10.6le", x);
Notons une différence de syntaxe importante avec printf : le & devant le nom de la variable, qui indique qu’on s’intéresse ici à l’adresse de
la variable, l’endroit où ranger la valeur saisie au clavier, et non pas à son
ancienne valeur.
affiche successivement :
— une valeur approchée de π sur 6 caractères (point de séparation décimale inclus) avec deux chiffres après la virgule. Comme 3.14 n’utilise
que 4 caractères, la fonction insère deux espaces avant les chiffres.
— la valeur de la variable x en notation scientifique, avec 14 chiffres
après la virgule, soit 3.00944434000000e+06, sur 20 caractères
en tout.
— la valeur de la variable x en notation scientifique, avec 6 chiffres après
la virgule, sur 10 caractères en tout, 3.0094e+06
remarque 1 : LabWindows est très peu tolérant avec les mélanges de
types, et aura une tendance certaine à planter si l’utilisateur rentre une lettre
alors qu’un nombre est attendu, ou un séparateur décimal . si un nombre
entier est attendu.
remarque 2 : quand on utilise deux instructions scanf successives pour
récupérer un nombre, puis un caractère ou une chaîne de caractères, on voit
apparaître un petit problème.
En effet, quand l’utilisateur rentre un nombre, il tape la suite de chiffres
correspondante puis appuie sur la touche « entrée » du clavier. La suite de
chiffres est transformée en un nombre, rangé dans la variable indiquée. Mais
printf("\n%20.14le", x);
}
3
6 opérations mathématiques
le caractère \n qui correspond à l’appui sur la touche « entrée » n’était pas
un chiffre, il est « gardé en mémoire ». Mais ce caractère convient au second
scanf, qui ne laisse donc pas le temps à l’utilisateur de taper sa réponse au
clavier.
Pour éviter tout problème, on fera précéder toutes les instructions scanf
par l’instruction fflush(stdin) qui signifier « vider (flush) l’entréestandard (stdin) », autrement dit vider la mémoire du clavier.
Beaucoup d’opérations ou fonctions mathématiques sont connues du C
ou de la bibliothèque de fonctions mathématiques du C et de LabWindows.
Citons quelques exemples :
— les quatres opérations +, -, *, /,
— le modulo % qui renvoie le reste de la division entre deux entiers,
— la fonction racine carrée sqrt,
— les fonctions trigonométriques sin, cos, tan, atan,
— les exponentielle et logarithme népérien exp, log, . . .
exemple : une séquence-type d’instructions pour saisir une valeur au clavier ressemblera donc à cela :
opérandes entières : On fera attention aux résultats de la division entre
deux entiers : a/b renvoie le quotient entier de la division, ainsi 5/2 renvoie 2. Si l’on souhaite obtenir un résultat correspondant à la division réelle,
il faut forcer l’une des deux opérandes à être un réel, par 5.0/2 ou par
(double)5/2, la deuxième syntaxe plus longue ayant l’avantage de fonctionner même si l’opérande est une variable.
main()
{
char reponse;
printf("Répondez par o ou n : ");
fflush(stdin);
scanf("%c",&reponse);
}
main()
{
int a=3;
A noter une exception de taille à la présence du & :
scanf("%s", chaine); range dans la variable chaine une chaîne
de caractères.
Il n’y a pas ici de & devant le nom de la variable, car le nom d’une variable de type « chaîne de caractères », ou plus généralement le nom de tout
tableau de valeurs, correspond déjà à une adresse.
Ainsi, scanf("%s", chaine); affecte la chaîne saisie au clavier à
la variable chaine. Attention, si la chaîne rentrée au clavier par l’utilisateur comporte des espaces, seule la partie précédant la première espace sera
prise en compte.
Pour permettre de saisir des chaînes de caractères comportant des espaces, on privilégiera l’instruction
gets(chaine)
qui n’a que des avantages par rapport à l’instruction scanf.
printf("%d",3/2);
printf("\n%lf",3.0/2);
printf("\n%lf",(double)3/2);
printf("\n%lf",(double)a/2);
}
affiche successivement 1, 1.5, 1.5, 1.5.
raccourcis : le C propose quelques raccourcis pour les additions
simples :
i++ est équivalent à l’instruction i=i+1,
i-- est équivalent à l’instruction i=i-1,
i+=5 est équivalent à l’instruction i=i+5.
4
7 instructions conditionnelles
Cls();
Tout programme informatique dépassant quelques lignes de code doit
pouvoir adapter son comportement aux résultats de calculs, aux réponses de
l’utilisateur. . .Le langage C dispose de deux types d’instructions pour cela.
printf("Rentrez un nombre : ");
scanf("%lf",&x);
printf("Le nombre %lf est ", x);
7.1 l’instruction if
if (x>0){ printf("positif."); }
else { printf("négatif ou nul."); }
L’instruction de base est le « si » : if :
}
exemple : if (x==0) { printf("x est nul"); }
Le fonctionnement est simple à comprendre : si la condition entre parenthèses est vérifiée, on exécute le bloc d’instruction qui suit (qui peut être une
instruction unique ou bien un ensemble d’instructions compris entre accolades).
Dans l’exemple ci-dessus, si la valeur de la variable x est nulle, le programme affiche le message x est nul, sinon, rien ne se passe et l’exécution du programme continue à l’instruction suivante.
Ici, on peut donc afficher deux messages différents, selon la valeur (et en
particulier ici, le signe) de la variable.
Notons au passage que l’obligation d’indiquer à l’instruction printf
les passages à la ligne est ici un avantage : on peut écrire une phrase unique
en combinant deux printf successifs : un affichage commun complété
d’une partie variable en fonction du résultat du test.
En plus de l’égalité (==), les tests peuvent utiliser les inégalités larges ou
strictes (>, <, >=, <=), la non-égalité (!=), les conjonctions « et » (&&) et
« ou » (||).
exemple 2 : résolution d’une équation du premier degré
exemples :
if (x!=0) { printf("x est non nul"); }
if (x==0 && y>=0){ printf("x nul et y positif");}
if (x>0 || y>0) { printf("x ou y -ou les deuxest strictement positif"); }
main()
{
double a, b;
printf("Résolution de l’équation ax+b=0");
printf("Rentrez a : ");
scanf("%lf",&a);
printf("Rentrez b : ");
scanf("%lf",&b);
7.2 le test if ...else
Un raffinement est un test du type « si . . .alors . . .sinon . . . » :
exemple 1 : test de positivité
if (a != 0){ printf("la solution est x=%lf", -b/a); }
else if (b==0){ printf("tout réel est solution"); }
else { printf("pas de solution"); }
main()
{
double x;
}
5
7.3 le test switch ...case
8 boucles
Pour tester successivement plusieurs valeurs d’une variable, on peut imbriquer les tests if ...else .... Par exemple, dans un menu permettant à l’utilisateur de choisir entre trois actions, on peut stocker le choix 1, 2
ou 3 dans une variable puis utiliser ceci :
Il est souvent utile de répéter une opération un grand nombre de fois : par
exemple, 10 fois, ou bien tant qu’une condition est vérifiée, en changeant
à chaque exécution seulement quelques paramètres. Pour cela on distingue
deux grandes familles de boucles : la boucle for et la boucle while.
Si, théoriquement, les deux sont équivalentes, leur usage en pratique diffère légèrement :
— on utilisera souvent la boucle for pour exécuter un nombre prédéfini de fois un bloc d’instructions dans lequel on aura besoin d’une
variable modifiée (incrémentée de 1, le plus souvent) à chaque exécution,
— on utilisera souvent la boucle while pour une boucle dont l’exécution est controlée par une condition booléenne.
if (c==1){ /* instructions si 1 */ }
else {
if (c==2) { /* instructions si 2 */ }
else {
if (c==3) { /* instructions si 3 */ }
else { /* instructions autres cas */ }
}
}
en remplaçant bien sûr les commentaires /* instructions */ par
les instructions appropriées.
Mais cette méthode, si elle fonctionne, donne un code lourd et peu lisible.
On préférera l’instruction switch ...case ... :
switch(c)
{
case 1: /* instructions si 1 */
case 2: /* instructions si 2 */
case 3: /* instructions si 3 */
default: /* instructions autres
}
8.1 la boucle for
C’est la boucle qui correspond à la phrase française « pour i allant de 0 à
9 par pas de 1, . . . ».
exemple 1 :
for ( i=0 ; i<10 ; i++ )
{ printf("Le compteur vaut maintenant %d", i); }
break;
break;
break;
cas */;
On voit qu’une boucle for comporte trois parties :
— le mot-clé for,
— entre parenthèses, les conditions d’éxécution de la boucle, ellesmêmes composées de trois éléments séparés par des points-virgules :
— l’initialisation i=0 : avant la première exécution de la boucle, on
affecte à une variable i préalablement déclarée la valeur 0.
— le test d’exécution i<10 : la boucle sera exécutée tant que i
gardera une valeur strictement inférieure à 10. Cette condition est
donc vérifiée avant chaque exécution de la boucle.
— la modification de la variable i++ : après chaque exécution de la
boucle, on modifie la valeur de i, ici en l’incrémentant de 1.
— entre accolades, les instructions proprement dites :
ici, à chaque itération (répétition) de la boucle, on affiche un message
comportant la valeur de la variable.
Ainsi, le programme regarde (switch) le contenu de la variable, et dans
chaque cas (case) exécute les instructions prévues. Le break est nécessaire pour reprendre l’exécution après le switch ...case ..., sans
examiner les cas suivants et en particulier le default, qui correspond aux
instructions à exécuter quand aucun des cas énumérés n’est apparu.
Attention, il est impossible de tester avec une instruction switch
...case autre chose que l’égalité du contenu d’une variable à des
constantes : pas d’inégalité, pas de tests composés à l’aide d’opérateurs « et »
(&&), « ou » (||), . . .
6
On peut imaginer des variantes :
8.2 la boucle while
exemple 2 :
Cette structure correspond à la phrase « tant que » : la boucle s’exécute
tant qu’une certaine condition est vérifiée.
for ( i=10 ; i<20 ; i=i+2 )
{ printf("Le compteur vaut maintenant %d", i); }
exemple 1 :
while ( reponse != ’n’ )
{ printf("Voulez-vous continuer (o/n) ?");
fflush(stdin);
scanf("%c",&reponse); }
exécute 5 fois la boucle avec une variable qui prend successivement les
valeurs 10, 12, 14, 16, 18.
exemple 3 :
for ( i=100 ; i>=0 ; i-- )
{
j = i/3;
if (3*j==i)
{ printf("%d est divisible par 3", i); }
}
Ici, tant que l’utilisateur ne répond pas n, la boucle continue de s’exécuter.
L’instruction fflush(stdin) permet de « vider l’entrée standard »
(voir plus haut).
exécute 101 fois la boucle, la variable prenant ses valeurs par ordre décroissant 100, 99, 98, . . ., 1, 0, mais seules les valeurs divisibles par trois
sont affichées.
Comment écrire la même chose en modifiant les instructions de contrôle
entre parenthèses pour enlever le test if ?
x=7;
while ( 1 )
{
x=x/2;
printf("%lf", x);
}
Il est très simple d’obtenir une boucle s’exécutant indéfiniment :
exemple 2 :
Que font les boucles suivantes :
exemple 4 :
for ( i=1 ; i>0 ; i++ )
{ printf("Le compteur vaut maintenant %d", i); }
La valeur numérique 1 correspond à la valeur de vérité « vrai », cette
boucle ne s’arrêtera jamais (ici, en affichant successivement 3.5, 1.75, 0.875,
. . .puis une fois atteinte la limite de précision du type double, une infinité
de 0).
exercice : comment fabriquer à l’aide d’une boucle while l’équivalent
d’une boucle for ?
et
exemple 5 :
remarque : Dans le premier exemple ci-dessus, il est nécessaire d’initialiser
reponse avant la boucle, pour s’assurer que cette variable ne contient
for ( i=100 ; i>=0 ; i=i-2 )
{ printf("Le compteur vaut maintenant %d", i); } pas, lors du premier test et avant même la première exécution de la boucle,
la valeur n ; si une affectation précédente, ou le hasard lors de la déclaration,
?
fait que la variable contient n, la boucle n’est pas exécutée du tout.
7
Il est ici plus simple d’utiliser une structure do ...while où le test
n’intervient qu’après la première exécution :
double carre(double x)
{
return x*x;
}
exemple 1 bis :
do { printf("Voulez-vous continuer (o/n) ?");
fflush(stdin);
scanf("%c",&reponse); }
while ( reponse != ’n’ )
main()
{
printf("%lf", carre(2.5));
}
9 fonctions
Ici donc on définit successivement une fonction carre en indiquant :
— qu’elle renvoie une valeur réelle (double),
— son nom (carre),
— qu’elle attend un paramètre réel, qui sera appelé x,
— la seule instruction exécutée : le carré de x est calculé par l’opération
x*x et renvoyé (retourné).
9.1 notion de fonction
Un programme en C est constitué d’une ou plusieurs fonctions, permettant de distinguer des tâches élémentaires. Ainsi, la fonction principale
main présente dans tous les programmes va à son tour appeler d’autres
fonctions pour réaliser le travail complexe demandé au programme.
Beaucoup de fonctions sont déjà fournies par l’environnement LabWindows (via les lignes #include présentes en début de programme), comme
printf pour réaliser des affichages, Cls pour effacer l’écran (la fenêtre
d’entrée-sortie plus précisément), etc.
Mais il est bien sûr possible d’en définir de nouvelles. . .
A l’intérieur de la fonction main, la fonction carre est appelée avec
le paramètre 2.5 pendant l’exécution de l’instruction printf, et le programme va donc afficher le résultat renvoyé par la fonction carre, soit
6.25.
9.3 compléments
9.2 définition d’une fonction
— comme pour les noms de variables, un nom de fonction commence
par une lettre et sera constitué de lettres (majuscules ou minuscules),
chiffres et tirets de soulignement.
— si plusieurs paramètres sont attendus, ils sont précisés successivement,
séparés par des virgules : (double x, double y, int a).
On ne peut pas, dans les paramètres d’une fonction, utiliser d’abréviation du type double x,y.
— par défaut, si aucun type n’est précisé devant le nom de la fonction,
LabWindows estimera qu’il s’agit d’un entier.
Pour écrire une fonction qui ne renvoie aucune valeur, il est donc
nécessaire de préciser qu’elle est de type vide (void) pour éviter
un avertissement : si la fonction n’est pas de type vide, l’instruction
return est attendue par le compilateur.
Schématiquement, une fonction est un petit programme qui prend en entrée zéro, un ou plusieurs paramètres, exécute une action (affichage, écriture
dans un fichier, calculs, etc.) et éventuellement retourne un résultat qui peut
être utilisé par la fonction appelante.
Pour définir une fonction, on doit indiquer quatre éléments :
— le type de la valeur renvoyée ;
— le nom de la fonction ;
— la liste des paramètres utilisés (nom et type) ;
— le corps de la fonction constitué des instructions à exécuter.
exemple : un exemple complet simple est la définition d’une fonction
carre qui calcule le carré d’un nombre :
8
— si une fonction peut demander plusieurs paramètres, il n’est pas possible simplement de faire en sorte qu’elle renvoie plusieurs valeurs.
— outre les paramètres, on peut définir au début de chaque fonction
des variables par des instructions du type double x;, exactement
comme pour la fonction main.
Par défaut, en C, les variables sont locales : elles n’existent qu’à l’intérieur de la fonction où elles sont définies, et ne sont pas connues
dans les fonctions appelantes ou appelées.
tion) et utilise une variable y pour stocker le résultat, calculé par les deux
formules possibles, l’une si x est nul, l’autre si x est non nul. Le résultat
calculé est ensuite retourné par l’instruction return y;.
Il est à noter que la variable a n’existe qu’à l’intérieur de la fonction
main() ; si l’on souhaite utiliser sa valeur, il faut comme ici la passer en
paramètre à la fonction sinc. De même, une fois revenu dans la fonction
main, après calcul du sinus cardinal, les variables x et y n’existent plus.
10 tableaux
exemple : on souhaite définir une fonction sinc qui renvoie le sinus
cardinal d’un nombre.
Une manière de procéder est la suivante :
Pour stocker plusieurs valeurs numériques, on peut bien sûr utiliser plusieurs variables, que l’on peut nommer a, b, c, ..., voire a1, a2,
a3, ...
Mais si l’on effectue des opérations concernant l’ensemble de ces variables (par exemple, affecter une valeur à chacune, calculer leur somme,
etc.) cette solution n’est absolument pas souple car elle oblige à prévoir, dès
l’écriture du programme, le nombre précis de valeurs qui seront à traiter, et
surtout d’écrire explicitement les expressions de type saisie de valeurs ou
somme. C’est encore possible si l’on a une poignée de valeurs, difficilement
praticable si le programme doit en traiter quelques dizaines, centaines, milliers, . . .
double sinc(double x)
{
double y;
if (x==0)
{ y=0;}
else
{ y=sin(x)/x; }
return y;
Le C, comme tous les langages de programmation, propose une structure
de données plus adaptée : les tableaux, autrement dit des variables indicées
par un nombre entier.
On peut déclarer un tableau ainsi :
double a[10];
Ainsi, dix variables réelles sont créées, a[0], a[1], ..., a[9].
On peut les manipuler, exactement comme les variables simples habituelles.
Bien sûr, les tableaux peuvent aussi être de type int, char, . . .Et le
nombre de valeurs n’est pas nécessairement 10. . .
}
main()
{
double a;
Cls;
printf("Rentrez un réel :");
scanf("%lf", &a);
printf("\n Le sinus cardinal de %lf est %lf",
a, sinc(a));
remarque : attention, si on déclare un tableau de 10 valeurs par l’instruction double a[10]; il n’existe pas de variable a[10] !
}
exemple 1 : Un avantage important de cette manière de procéder est de
permettre de traiter toutes les valeurs à l’aide d’une boucle. L’instruction :
Ainsi, la fonction prend un paramètre x (fourni lors de l’appel de la fonc9
La méthode informatique correspond à ce qui aurait été fait à la main :
on détermine un certain nombre d’abscisses régulièrement réparties sur l’intervalle, que l’on place dans un tableau X. Puis on calcule les ordonnées
correspondantes, placées dans un tableau Y.
Il ne reste alors plus qu’à faire appel à une ou plusieurs instructions qui
vont placer les points correspondants dans une fenêtre graphique et les relier
entre eux.
for (i=0; i<10; i++){ a[i]=0; }
affecte ainsi à chaque variable - à chaque case du tableau - la valeur nulle.
On évite ainsi de devoir écrire les dix instructions a[0]=0;, . . ., a[9]=0;
exemple 2 : une pratique utile, en particulier pour tracer des courbes, est
de placer dans un tableau n valeurs régulièrement réparties entre deux réels
a et b. On utilisera pour cela l’instruction :
for (i=0; i<n; i++) { X[i]=a+ i*(b-a)/(n-1); }
exemple 3 : l’utilisation d’une boucle permet aussi de calculer facilement
la somme des valeurs d’un tableau : si l’on dispose d’un tableau X avec n
valeurs, et d’une variable s, on peut procéder ainsi :
11.1 solution simple
Le programme suivant présente une solution simple pour réaliser le tracé
graphique de exp sur [-1,1] :
s=0;
for (i=0; i<n; i++){ s = s + X[i]; }
main()
{
double X[200], Y[200];
int i;
A la fin de l’exécution de ce bout de programme, la variable s contient
bien la somme des éléments du tableau.
exemple 4 : une chaîne de caractères est un tableau de caractères, et il
est donc possible de manipuler les caractères un par un ; par exemple
for (i=0; i<200; i++)
{
X[i] = -1 + 2.0*i/199;
/* Attention, le 2.0 est obligatoire ici :
sinon, 2 et i étant entiers, le calcul de 2*i/199
renverrait une valeur entière (troncature,
sans décimale, de la valeur exacte) */
Y[i] = exp(X[i]);
}
char message[20];
gets(message);
for (i=0; i<20; i++)
{ printf("%c : %d\n", message[i], message[i]); }
affiche 20 lignes, listant les 20 caractères de la chaîne suivi de leur code
ASCII.
XYGraphPopup("premier tracé", X, Y, 200,
VAL_DOUBLE, VAL_DOUBLE);
}
11 graphiques
Etant donnée une fonction - qui peut être l’une des fonctions déjà connues
du langage (comme sin, sqrt, exp, . . .) ou bien une fonction écrite pour
l’occasion (par exemple sinc)- on souhaite en tracer le graphe sur un intervalle donné.
La fonction XYGraphPopup (spécifique à LabWindows) s’occupe de
tout. . .Il suffit de lui fournir deux tableaux de valeurs et de lui indiquer le
nombre de points à tracer.
10
11.2 solution souple
VAL_EMPTY_SQUARE, VAL_SOLID, 1, VAL_RED);
GetKey();
La solution précédente a l’avantage d’être très simple à mettre en oeuvre,
mais l’inconvénient que l’on ne maîtrise pas du tout l’aspect de l’affichage
(couleurs, dimensions, échelles, . . .).
}
Ici, la fonction NewPanel crée une fenêtre dont on détermine le titre,
la position initiale (à 10 pixels du haut de l’écran et 20 du bord gauche) et
les dimensions (600 pixels de haut et 800 de large). De plus la fonction renvoie un identifiant (un nombre entier) pour cette fenêtre, que l’on range dans
une variable. Puis cette fenêtre est affichée par la fonction DisplayPanel
dont le paramètre est justement l’identifiant précedemment attribué à la fenêtre.
A l’intérieur de la fenêtre, une zone graphique est affichée : à 10 pixels du
haut de la fenêtre, 20 du bord gauche, avec une hauteur de 550 pixels et une
largeur de 750, par les instructions NewCtrl et SetCtrlAttribute.
Puis l’instruction PlotXY trace la courbe. Mais on voit que le nombre
de paramètres est plus important que pour la fonction XYGraphPopup :
on peut choisir l’aspect des traits (lignes continue, pointillé, . . .), des points
(marqués ou non), la couleur. . .
Il est possible de remplacer l’instruction unique XYGraphPopup par
une série d’instructions qui vont successivement :
— définir une fenêtre,
— l’afficher,
— définir dans cette fenêtre une (ou plusieurs) zones graphiques,
— régler la taille de cette zone graphique
— effectuer un tracé dans cette zone graphique.
Le bout de code suivant illustre cela :
main()
{
double X[200], Y[200];
int i;
int fenetre, zone;
12 fichiers
for (i=0; i<200; i++)
{
X[i] = -1 + 2.0*i/199;
Y[i] = exp(X[i]);
}
12.1 généralités
Les données calculées par un programme peuvent être archivées, ou bien
traitées des heures ou des jours plus tard par un autre programme. . .Il sera
pour cela nécessaire de savoir les écrire ou les relire dans un fichier.
fenetre = NewPanel(0, "fenetre de tracé",
10, 20, 600, 800);
DisplayPanel(fenetre);
12.2 écriture
L’opération la plus simple est l’écriture dans un fichier.
zone = NewCtrl(fenetre, CTRL_GRAPH,
"zone de tracé", 10, 20);
SetCtrlAttribute(fenetre, zone, ATTR_HEIGHT, 550);
SetCtrlAttribute(fenetre, zone, ATTR_WIDTH, 750);
exemple 1 : dans cet exemple, on se contente d’écrire un message dans
un fichier.
main()
{
FILE *fichier;
PlotXY(fenetre, zone, X, Y, 200,
VAL_DOUBLE, VAL_DOUBLE, VAL_THIN_LINE,
11
fichier = fopen("Z:\\Info_S2\\essai.txt", "w");
fprintf(fichier, "Test de la fonction fprintf");
fclose(fichier);
}
Ici les valeurs contenues dans le tableau sont écrites les unes à la suite des
autres dans le fichier (avec ce programme, les valeurs de X n’étant pas initialisées, le contenu du fichier sera sans grand intérêt : mélange « aléatoire »
de 0 et de valeurs du type 1.2994944e+261. . .).
}
Les trois étapes du programme sont donc :
— l’ouverture par la fonction fopen du fichier dont le chemin d’accés
est passé en paramètre. Le chemin d’accés réel est en fait ici
Z:\Programmation\essai.txt
mais il est nécessaire de doubler les \ car ceux-ci sont des caractères
spéciaux.
Le "w", pour « write » indique que le fichier est ouvert (créé s’il
n’existe pas, et préalablement vidé s’il existe déjà) pour écriture.
Un identifiant est attribué et rangé dans une variable fichier (d’un
type spécifique FILE). Dorénavant, le programme ne fera plus référence au chemin d’accés du fichier sur le disque, mais uniquement à
cet identifiant.
— L’écriture dans le fichier, par la fonction fprintf, très analogue à la
fonction printf, qui exige comme argument supplémentaire l’identifiant du fichier dans lequel écrire.
— Puis, une fois l’écriture terminée, on signale au système que le fichier
est traité, par l’instruction fclose.
12.3 lecture, version 1
On peut avoir besoin de relire des données écrites lors d’une séance de
mesures quelques jours avant, ou fournies par un autre technicien.
La méthode s’inspire naturellement de ce qui précède :
main()
{
FILE *fichier;
double X[200];
int i;
fichier = fopen("Z:\\Info_S2\\essai.txt", "r");
for (i=0; i<200; i++)
{ fscanf(fichier, "%lf\n", &X[i]); }
fclose(fichier);
}
Quand, comme souvent, les données à sauvegarder sont des valeurs numériques rangées dans un tableau (typiquement, une série de mesures, ou
bien les coordonnées d’un grand nombre de points), on combine le programme précédent avec une boucle :
Il s’agit de relire des données, donc le w de « write » est devenu un r pour
« read », et le fprintf est devenu un fscanf.
Bien entendu, pour fonctionner ce programme nécessite la présence d’un
fichier essai.txt au bon emplacement et contenant 200 valeurs numériques rangées à raison d’une par ligne.
main()
{
FILE *fichier;
double X[200];
int i;
12.4 lecture, version 2
Le principal défaut du programme précédent est qu’il nécessite de
connaître à l’avance le nombre de valeurs présentes dans le fichier.
Si tel n’est pas le cas, et que l’on connaît seulement une borne supérieure
à ce nombre de données, on peut procéder un peu différemment : la boucle
fichier = fopen("Z:\\Info_S2\\essai.txt", "w");
for (i=0; i<200; i++)
{ fprintf(fichier, "%lf\n", X[i]); }
fclose(fichier);
12
for, exécutée autant de fois que le nombre de données, peut être remplacée par une boucle while qui sera exécutée « tant que » le fichier contient
encore des données.
Une image (noir et blanc) sera représentée par une matrice (un tableau de
lignes et colonnes). Chaque case, correspondant à un point de l’image, sera
d’un type de données nouveau : des unsigned char, soit des entiers
compris entre 0 et 255. La valeur 0 correspond à un pixel noir, la valeur 255
à un pixel blanc, et les différentes opérations sur les images vont consister à
modifier ou ranger différemment ces valeurs.
main()
{
FILE *fichier;
double X[200];
int i;
On précisera en début de programme la taille des images (fixée une fois
pour toute dans le programme) :
#define LARGEUR 400
#define HAUTEUR 266
fichier = fopen("Z:\\Info_S2\\essai.txt", "r");
puis on incluera les bibliothèques
i=0;
while (!feof(fichier))
{
fscanf(fichier, "%lf\n", &X[i]);
i++;
}
fclose(fichier);
#include <ansi_c.h>
#include <X:\Info_S2\ImagesMph.h>
et enfin on déclarera deux variables pour disposer de deux images (typiquement, un original et une image modifiée) :
unsigned char Image[HAUTEUR][LARGEUR];
unsigned char ImageTrans[HAUTEUR][LARGEUR];
}
feof est la fonction qui teste si l’on est arrivés à la fin du fichier. Et le !
est la négation : l’instruction signifie donc « tant que l’on n’est pas à la fin
du fichier », on lit un nombre supplémentaire dans le fichier, que l’on range
dans la variable X[i], et on augmente l’indice i de 1.
Ainsi, à la fin de cette boucle, la variable i contient le nombre de données
lues, et ces données sont rangées dans le tableau X.
Bien entendu, si le nombre de données est strictement supérieur à 200
dans le fichier, le programme ne fonctionnera pas correctement. Mais en revanche il est capable de lire correctement tout fichier contenant entre 0 et
200 nombres réels.
Alors la fonction
ChargeImage("image.bmp", Image)
permet de placer dans la matrice Image l’image contenue dans le fichier
image.bmp, et
AfficheImage(Image,"mon titre", T, G)
affiche une image dans une fenêtre dont le bord supérieur gauche est à T
pixels du haut et G pixels de la gauche du coin supérieur gauche de l’écran.
Il est donc possible maintenant de créer une image blanche, noire, de passer en négatif une image, de faire des inversions droite-gauche ou haut-bas,
d’augmenter la luminosité, le contraste d’une image, de l’accentuer (rendre
plus nette), . . .
13 traitement d’images
L’utilité des outils précédents peut être illustrée de manière visuelle par
quelques algorithmes simples de traitement d’images.
exemples :
13
applique une symétrie à l’image,
for (i=0; i<HAUTEUR; i++)
for (j=0; j<LARGEUR; j++)
{ ImageTrans[i][j] = 255 - Image[i][j]; }
for (i=0; i<HAUTEUR; i++)
for (j=0; j<LARGEUR; j++)
{ ImageTrans[i][j] = Image[i][j] + 10; }
crée un négatif de l’image initiale,
for (i=0; i<HAUTEUR; i++)
for (j=0; j<LARGEUR; j++)
{ ImageTrans[i][j] = Image[i][LARGEUR-1-j]; }
Guillaume Laget
-
éclaircit l’image
(ou presque : quel défaut constate-t-on ? Comment le corriger ?)
version du 27-08-2014 11:36 (document mis à jour sur http ://maths.tetras.org/)
14
-
réutilisation et reproduction non commerciale de tout ou partie de ce document vivement encouragées
informatique - S1
TP 1 - premiers pas en C
1. sinus cardinal et cosinus redressé
On considère le programme suivant :
#include <ansi_c.h>
main()
{
double x,y;
printf("\nRentrez une valeur de x : ")
scanf("%lf", x);
if (x=0);
{y == 1;}
else
{y=sin(x)/x;}
département Mesures Physiques - IUT1 - Grenoble
4. pilotage d’un générateur BF
Écrire un programme qui demande à l’utilisateur une fréquence
(nombre entier, par exemple 100), une tension (nombre entier, par
exemple 10), un offset (nombre entier, par exemple 5) et un type de signal (chaîne valant "SIN", "TRI", "SQ"), puis affiche une commande
du type OUTP:LOAD INF;:APPL:SIN 100Hz, 10Vpp, 5V
en passant à la ligne.
5. la boucle for
On considère le programme suivant :
#include <ansi_c.h>
main()
{
int i;
for (i=0 ; i<10 ; i++)
{
printf("%d\n",i);
}
printf("\nsinus_cardinal(%lf)=%lf, x, y);
}
(a) Corriger les erreurs de syntaxe.
(b) À quoi sert l’instruction scanf ? Le symbole == ?
(c) Quelle est l’effet de ce programme ? L’exécuter.
2. équation du second degré
Écrire un programme qui permet à l’utilisateur de saisir trois valeurs
réelles a, b et c, puis affiche le discriminant et les solutions réelles de
l’équation ax2 + bx + c = 0. Si l’équation n’a pas de solution afficher
un message pour l’indiquer.
3. affichage d’un réel
Écrire un programme qui demande à l’utilisateur un réel sous forme
décimale et l’affiche ensuite sous forme scientifique avec 5 chiffres
significatifs.
}
(a) L’exécuter pas-à-pas pour en comprendre le fonctionnement,
(b) Le modifier pour afficher, du plus grand au plus petit, les nombres
compris entre 16 et -3,
(c) Le modifier pour qu’il affiche 10 valeurs régulièrement réparties
entre 2.5 et 4.8
6. trigonométrie
Écrire les fonctions module et argument qui, partant de deux paramètres réels a et b renvoient respectivement le module et l’argument
du nombre complexe correspondant a + ib.
7. conversion entre coordonnées
comme paramètres un réel x et un entier positif n, et qui renvoie la valeur de x élevé à la puissance n.
Écrire les fonctions Abscisse, Ordonnee, Cote qui renvoient les
coordonnées cartésiennes d’un point défini par ses coordonnées latitude, longitude et altitude, selon les formules

 x = (R + h) cos(l) cos(L)
y = (R + h) cos(l) sin(L)

z = (R + h) sin(l)
9. la fonction sinus cardinal
Écrire une fonction sinc qui calcule les valeurs du « sinus cardinal »
sin x
sinc(x) =
si x 6= 0, sinc(0) = 1.
x
10. facultatif : suite de Syracuse
Écrire un programme qui demande à l’utilisateur de choisir un entier
u0 puis affiche successivement les termes de la suite (un ) définie par

un

si un est pair,
2
un+1 =
 3un + 1
sinon.
2
avec l la latitude, L la longitude, et h l’altitude. R = 6378000m est le
rayon de la Terre.
Quelle est l’abscisse de la salle 301 du département Mesures Physiques ?
8. puissance entière
1) Écrire un programme qui demande à l’utilisateur un entier strictement positif n et un réel x, puis affiche la valeur de xn .
2) Modifier le programme pour qu’il fonctionne correctement pour un
entier n quelconque (positif, négatif ou nul).
3) Transformer ce programme en une fonction puissance qui prend
Le tester avec plusieurs valeurs pour u0 . Que remarque-t-on ?
11. facultatif : équation du second degré à solutions complexes
Reprendre le programme sur l’équation du second degré pour afficher,
si le discriminant est négatif, les solutions complexes.
2
informatique - S1
TP 2 - tableaux, graphiques, fichiers
1. cosinus redressé double alternance
(a) Écrire une fonction CosRed2 donnant les valeurs du « cosinus redressé double alternance » : cos(x) si cos(x) > 0, − cos(x) sinon.
(b) Remplir un tableau X avec 200 valeurs régulièrement réparties
entre −2π et 2π.
(c) Remplir un tableau Y avec les valeurs correspondantes du cosinus
redressé double alternance.
(d) Tracer la courbe représentative du cosinus redressé double alternance.
2. courbe de Lissajous
Tracer de même la courbe d’équations paramétriques, pour t ∈
[0, 2π] :
x(t) = cos(t)
y(t) = sin(4t)
en plaçant dans des tableaux X et Y les valeurs d’abscisses et d’ordonnées correspondant à 200 instants régulièrement répartis entre 0 et
2π.
3. détermination d’incertitudes de mesure
(a) Tracer sur un même graphique, pour 0 ≤ ϕ ≤ π/2,
p
p
1 + sin2 (ϕ)
2
2
.
y = 1 + π /ϕ
et
y=
ϕ| cos(ϕ)|
département Mesures Physiques - IUT1 - Grenoble
(b) Déterminer graphiquement les intersections de ces deux courbes à
une précision de 10−2 . Quelles sont les valeurs en degré correspondantes ?
4. résolution numérique par dichotomie
On rappelle que si une fonction f continue sur [a, b] est strictement
monotone, avec f (a) et f (b) de signes opposés, alors elle admet un
unique zéro sur l’intervalle. L’algorithme de dichotomie suivant permet de déterminer des valeurs approchées de ce zéro.
Il consiste à définir deux suites (xn ) et (yn ) adjacentes, avec (xn )
croissante, (yn ) décroissante, et dont la limite commune est le zéro
cherché.
Pour cela on pose x0 = a, y0 = b puis, si xn et yn sont calculées,
on note m le milieu de l’intervalle [xn , yn ]. Si f (xn ) et f (m) sont
de signes opposés, le zéro est entre xn et m : on pose xn+1 = xn ,
yn+1 = m. Dans le cas contraire, on posera xn+1 = m, yn+1 = yn .
Comment tester « informatiquement » si f (xn ) et f (m) sont de même
signe ?
Implémenter cet algorithme.
5. courbe de valeurs lues dans un fichier
Lire dans le fichier courbe.txt 200 valeurs d’abscisse et ordonnée
(rangées à raison d’une abscisse et d’une ordonnée, séparées par une
espace, sur chaque ligne), les ranger dans des tableaux X et Y, et tracer
la courbe correspondante.
informatique - S1
TP 3 - calculs de moyennes, écarts-type, variances
1. fonction de lecture :
Créer une fonction Lecture1 qui prend comme paramètres un tableau de réels et une chaîne de caractères nom et qui :
- range dans le tableau les valeurs lues dans le fichier nom
- renvoie le nombre de valeurs lues.
2. moyenne : écrire une fonction Moyenne1 qui prend comme paramètre un tableau X et un entier n et renvoie la moyenne des n premières valeurs du tableau.
3. variance : écrire une fonction Variance1 qui prend comme paramètre un tableau X et un entier n et renvoie la variance des n premières
valeurs du tableau.
4. écart-type : écrire une fonction EcartType1 qui prend comme paramètre un tableau X et un entier n et renvoie l’écart-type des n premières valeurs du tableau.
5. calculs statistiques : écrire un fonction main() qui, en utilisant ce
qui précède :
- fait choisir un fichier à l’utilisateur à l’aide de la fonction
FileSelectPopup(),
- place les nombres contenus dans ce fichier dans un tableau,
- affiche la moyenne, la variance et l’écart-type de la série statistique.
6. à deux variables : écrire de même des fonctions Lecture2,
Moyenne2, Variance2 et EcartType2 qui permettent de cal-
département Mesures Physiques - IUT1 - Grenoble
culer les moyennes, variances et écart-type des n premières valeurs
contenues dans un tableau X, pondérées par les coefficients correspondants d’un tableau Y, à partir d’un fichier qui contient sur chaque
ligne une note et le coefficient associé.
Rappels :
— pour une série statistique (xi ), la moyenne est
x̄ =
x1 + . . . + xp
,
p
la variance est
(x1 − x̄)2 + . . . + (xp − x̄)2
,
p
l’écart-type est la racine carrée de la variance.
— pour une série statistique (xi , ni ), la moyenne est
x̄ =
n1 x1 + . . . + np xp
,
n1 + . . . + np
la variance est
n1 (x1 − x̄)2 + . . . + np (xp − x̄)2
,
n1 + . . . + np
l’écart-type est la racine carrée de la variance.
informatique - S1
TP 4 - GPS
À partir de la trace enregistrée par un GPS, on récupère le parcours d’un
randonneur sous la forme d’un fichier contenant, sur chaque ligne, la latitude
l, la longitude L et l’altitude h des points successifs.
Dans un premier temps, on considèrera que la Terre est une sphère de
rayon R = 6378000m.
On a alors les formules de conversion en coordonnées cartésiennes :

 x = (R + h) cos(l) cos(L)
y = (R + h) cos(l) sin(L)

z = (R + h) sin(l)
1. Les randonnées considérées durent au maximum 10 heures, et un
point est enregistré toutes les 10 secondes.
Définir en début de programme une constante NBP plus grande que le
nombre maximal de points à considérer.
département Mesures Physiques - IUT1 - Grenoble
(a) permet à l’utilisateur de choisir un fichier
(b) relit le fichier
(c) trace, en deux graphiques dans la même fenêtre : le trajet parcouru
(représenter la latitude et la longitude), et le profil d’altitude (représenter l’altitude)
(d) calcule et place dans 3 tableaux X, Y, Z les coordonnées cartésiennes des points lus dans le fichier
(e) calcule la distance totale parcourue lors de la randonnée, le dénivelé positif et le dénivelé négatif
4. Écrire une fonction Distance qui prend comme paramètres six réels
X1, Y1, Z1, X2, Y2, Z2, et renvoie la distance entre les deux points
de coordonnées respectives (X1, Y1, Z1) et (X2, Y2, Z2).
6. Les coordonnées latitude, longitude et altitude fournies par le GPS
font en fait référence non pas à une sphère, mais à un ellipsoïde
de demi-grand-axe a = 6378137.00m,
de demi-petit-axe b =
√
6356752.31m, d’excentricité e = a2 − b2 /a = 0.08181919, d’apa−b
= 1/298.2572.
platissement f =
a
On obtient alors les formules de conversion :

a

+ h) cos(l) cos(L)
x = (p


2 sin2 (l)

1
−
e



a
y = (p
+ h) cos(l) sin(L)
1 − e2 sin2 (l)



a(1 − e2 )


p
+ h) sin(l)
 z = (

1 − e2 sin2 (l)
5. Écrire une fonction principale qui, en utilisant les fonctions précédentes :
Comparer les valeurs obtenues par ces formules avec celles obtenues
pour le modèle sphérique.
2. Écrire une fonction qui permet de relire les valeurs contenues dans
le fichier, de les placer dans trois tableaux l, L et h, en renvoyant le
nombre de lignes lues.
3. Écrire une fonction Abscisse qui prend comme paramètre trois
réels (latitude, longitude, altitude) et renvoie l’abscisse correspondante.
Écrire de même la fonction Ordonnee et la fonction Cote.
informatique - S1
TP 5 - traitement d’images
En début de programme vous placerez le code :
#include <ansi_c.h>
#define LARGEUR 400
#define HAUTEUR 266
#include <X:\Info_S2\ImagesMph.h>
pour bénéficier des deux fonctions :
ChargeImage("image.bmp", Image)
qui place dans la matrice Image l’image contenue dans le fichier
image.bmp, et
AfficheImage(Image,"mon titre", T, G)
qui affiche l’image représentée par la matrice Image dans une fenêtre dont
le bord supérieur gauche est à T pixels du haut et G pixels de la gauche du
coin supérieur gauche de l’écran.
Puis, pour disposer de deux images (originale et modifiée) :
unsigned char Image[HAUTEUR][LARGEUR];
unsigned char ImageTrans[HAUTEUR][LARGEUR];
Une image, monochrome, sera donc représentée par une matrice
d’unsigned char, soit des entiers compris entre 0 et 255 : 0 indique
un pixel noir, 255 un pixel blanc.
Pour vos essais utiliser les images fournies ou vos propres images (au
format bitmap (bmp), de dimensions imposées HAUTEUR x LARGEUR ;
les couleurs seront transformées en niveaux de gris).
département Mesures Physiques - IUT1 - Grenoble
1. Quelques manipulations élémentaires pour commencer :
(a) Relire et afficher l’une des images fournies.
(b) Créer et afficher une image blanche.
(c) Créer et afficher une image avec une bande blanche en haut, une
bande centrale grise et une bande noire en bas.
2. Appliquer à une image les transformations élémentaires suivantes, en
affichant côte à côte l’image originale et l’image transformée.
négatif : transformer le blanc en noir et le noir en blanc.
symétrie ; inverser droite et gauche.
luminosité : éclaircir/assombrir d’une valeur choisie par l’utilisateur
(par exemple, entre -20 et +20).
contraste : assombrir les pixels sombres et éclaircir les pixels clairs.
3. De même, implémenter deux filtres plus complexes :
accentuation (renforcement de netteté) : remplacer le niveau de
chaque pixel par la combinaison de son niveau coefficient 1 + 4r
et des niveaux des quatre voisins (gauche, droite, haut, bas) coefficient −r. Tester pour plusieurs valeurs de r, de 0.1 à 2.
détection de contours : dessiner les contours de l’image.
4. Histogramme :
Afficher l’histogramme d’une image (en abscisse les 256 niveaux de
gris, en ordonnée le nombre de pixels de cette couleur).

Documents pareils