Nous disposons d'une urne contenant n billes numérotées et nous souhaitons effectuer p tirages sans remise depuis cette urne.
Le nombre de combinaisons possibles est calculé à l'aide de la formule :
On demande d'écrire un programme en pascal qui saisit deux entiers n et p, avec (0 ≤ p ≤ n ≤ 12), puis calcule et affiche le nombre de combinaisons de p parmi n.
Début combinaisons Répéter Ecrire("Donner n [0, 12] : ") Lire(n) Jusqu'à (n dans [0..12]) Répéter Ecrire("Donner p [0, ", n, "] : ") Lire(p) Jusqu'à (p ≥ 0) et (p ≤ n) { Calcul de n! } fn ⟵ 1 Pour i de 1 à n Faire fn ⟵ fn * i Fin pour { Calcul de p! } fp ⟵ 1 Pour i de 1 à p Faire fp ⟵ fp * i Fin pour { Calcul de (n-p)! } fnp ⟵ 1 Pour i de 1 à (n-p) Faire fnp ⟵ fnp * i Fin pour cnp ⟵ fn div (fp * fnp) Ecrire("C(", n, ", ", p, ") = ", cnp) Fin combinaisons
La solution donnée présente quelques inconvénients :
Répétition : Certaines parties du code ont été répétées plusieurs fois.
Cette répétition devient vite une source d’erreurs non détectables facilement, à force de copier/coller certaines portions de code.
Lisibilité : Le programme principal devient de plus en plus long et illisible au fur et à mesure que le problème devienne plus compliqué.
D’une part, La longueur du programme influe mal sur sa lisibilité, surtout si on omet l’indentation du code. D’autre part, on ne sait plus quelle est la fonction de certaines portions du programme.
La solution donnée peut être améliorée en utilisant des modules pour éviter les répétitions dans certaines portions de code et, du même coup, améliorer la lisibilité du programme.
Les modules sont, aussi, le moyen recommandé pour la décomposition d’un problème compliqué en des sous-problèmes plus facile à résoudre.
Les modules sont aussi appelés sous-programmes. En algorithmique et en Pascal on distingue deux types de sous-programmes : les procédures et les fonctions.
Dans la suite de ce chapitre nous commencerons par présenter les fonctions et les procédures. Nous continuerons, la suite du chapitre, avec le type des paramètres et leurs modes de passage. Et nous terminerons par présenter un exemple d’analyse modulaire.
Une fonction est un sous-programme qui renvoie un seul résultat en fonction de ses paramètres. Les paramètres d’une fonction sont, généralement, transmis par valeur.
Écrire une fonction qui renvoie la valeur de f(x) pour la fonction : f(x) = 3.x²-4.x+1
{En algorithmique} DEF FN f(x:réel):réel f ⟵ 3*x*x-4*x+1 Fin f
{En Pascal} function f(x:real):real; begin f := 3*x*x-4*x+1; end;
Une procédure est un sous-programme qui ne renvoie aucun résultat. Les paramètres d’une procédure sont transmis soit par valeur, soit par variable.
Lorsque les paramètres d’une procédure sont passés par variable, elle peut les changer.
Il est, donc, possible d’exploiter cette propriété pour renvoyer un ou plusieurs résultats au programme appelant.
Écrire une procédure permettant de saisir une valeur comprise entre 20 et 30.
{En algorithmique} DEF PROC SaisieValeur(var n: entier) Répéter Ecrire("Donner n [20, 30] :") Lire(n) Jusqu’à (n ≥ 20) et (n ≤ 30) Fin SaisieIntervalle
{En Pascal} Procedure SaisieValeur(var n : integer); begin Repeat Write('Donner n [20, 30] :'); Readln(n); Until (n >= 20) and (n <= 30); end;
Un sous-programme défini réellement un ensemble de traitements effectués sur des données. Ces données doivent être passées au sous-programme dans ses paramètres.
On distingue deux types de paramètres :
{Paramètres formels}
DEF PROC Permuter(var a, b : entier)
aux ⟵ a
a ⟵ b
b ⟵ aux
FIN Permuter
{Paramètres effectifs}
Pour i de 1 à n-1 Faire
Pour j de 1 à n-1 Faire
Si t[i]>t[i+1] Alors
Proc Permuter(t[i], t[i+1])
Fin Si
Fin Pour
Fin Pour
Il existent deux modes de passage des paramètres : par variable ou par valeur.
Lors d’un passage par valeur, la valeur de l'expression passée en paramètre est copiée dans une variable locale. C'est cette variable qui est utilisée pour faire les traitements dans le sous-programme appelé.
{Dans une fonction} DEF FN U(n:entier):réel U ⟵ n*(n+1)/2 Fin U
{Dans une procédure} DEF PROC Afficher(a, b : entier) Ecrire(a, "+", b, "=", (a+b)) Fin Afficher
Le passage par variable consiste à passer les variables elles-mêmes. Toute modification du paramètre dans la fonction appelée entraîne, alors, la modification de la variable passée en paramètre.
Remarque : Bien qu’il soit possible d’utiliser le mode de passage de paramètres par variable avec les fonctions, il est fortement recommandé de l’éviter et ce pour des raisons pédagogiques.
DEF PROC Incrementer(var n:entier; pas:entier) n ⟵ n + pas Fin U
DEF PROC Remplir(n : entier; var t : tab) Pour i de 1 à n Faire t[i] ⟵ Alea(50) + 1 Fin Pour Fin Afficher
Nous disposons d'une urne contenant n billes numérotées et nous souhaitons effectuer p tirages sans remise depuis cette urne.
Le nombre de combinaisons possibles est calculé à l'aide de la formule :
On demande d'écrire un programme en pascal qui saisit deux entiers n et p, avec (0 ≤ p ≤ n ≤ 12), puis calcule et affiche le nombre de combinaisons de p parmi n, en utilisant une approche modulaire.
Le problème peut être décomposé comme suit :
La résolution du problème se réduit, maintenant, à l’écriture des sous-programmes présentés dans la figure ci-dessus.
{P.P} Résultat = Ecrire("C(", n, ", ", p, ") = ", c) c ⟵ fn cnp(n, p) n = Proc Saisie(n, 12) p = Proc Saisie(p, n) Fin PP
TDO | |
---|---|
Objet | Type/Nature |
n, p, c | entier |
DEF PROC saisie(var n : entier; max : entier) Répéter Ecrire("Donner un entier [0, ", max, "] : ") Lire(n) Jusqu'à (n ≥ 0) et (n ≤ max) Fin Saisie
TDO | |
---|---|
Objet | Type/Nature |
DEF FN cnp(n, p : entier): entier cnp ⟵ fn fact(n) div (fn fact(p) * fn fact(n-p)) Fin cnp
TDO | |
---|---|
Objet | Type/Nature |
DEF FN fact(n : entier): entier f ⟵ 1 Pour i de 2 à n faire f ⟵ f * i Fin Pour fact ⟵ f Fin cnp
TDO | |
---|---|
Objet | Type/Nature |
f, i | entier |
Remarque : Les variables utilisées dans un sous-programme sont appelées des variables locales, elles sont définies uniquement à l’intérieur du sous-programme.
program combinaisons; procedure Saisie(var n : integer; max : integer); begin repeat Write('Donner un entier [0, ', max, '] : '); Readln(n); until (n >= 0) and (n <= max); end; function fact(n : integer):longint; var i : integer; f : longint; begin f := 1; for i:=2 to n do f := f * i; fact := f; end; function cnp(n, p : integer):longint; begin cnp := fact(n) div (fact(p) * fact(n-p)); end; var n, p : integer; c : longint; begin Saisie(n, 12); Saisie(p, n); c := cnp(n, p); Writeln('C(', n, ', ', p, ') = ', c); Readln; end.