Aspects d'algorithmique de base
-
Upload
roland-yonaba -
Category
Documents
-
view
512 -
download
4
Transcript of Aspects d'algorithmique de base
Quelques aspects d’algorithmique de base Et implémentation en Turbo Pascal
Roland Yonaba Etudiant en Master 1 – Option Eau – 2010-2011
29/11/2010
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
1
Quelques aspects d’algorithmique de base
Et implémentation en Turbo-Pascal
Par Roland O Yonaba
Etudiant au 2IE en Master 1 – Option Eau (Année 2010-2011)
E-mail : [email protected]
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
2
Sommaire
I. Calculs et opérations numériques ................................................................................................... 4
1. Somme d’entiers entre deux bornes définies ............................................................................. 6
2. Somme d’entiers de 1 à n ............................................................................................................ 8
3. Calcul d’une factorielle ................................................................................................................ 9
4. Calcul de ............................................................................................................................... 12
5. Les nombres parfaits ................................................................................................................. 14
6. PGCD de deux entiers A et B ..................................................................................................... 16
7. PPCM de deux entiers A et B ..................................................................................................... 20
8. Combinaisons de p-uplets dans un ensemble n-uplets............................................................. 21
9. Test de primalité d’un entier positif N ...................................................................................... 22
10. Conjecture de Goldbach ........................................................................................................ 24
11. Définir une fonction polynomiale de degré N ....................................................................... 25
12. Les nombres d’Armstrong ..................................................................................................... 27
II. Itérations, Convergence, Conversions, Approximations, simulations de problèmes ................... 28
1. Approximation de la « divine proportion ». .............................................................................. 30
2. Simulation de lancer d’une pièce de monnaie .......................................................................... 32
3. Approximation de Pi par la méthode statistique ...................................................................... 34
4. Calcul Intégral d’une fonction polynomiale .............................................................................. 37
5. Table de Gauss ........................................................................................................................... 40
En conclusion… ...................................................................................................................................... 43
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
3
L’objet de la programmation est le plus souvent la résolution certaines situations complexes,
pour peu qu’elles soient modélisables, par l’automatisation d’un long processus de calcul. A cet effet,
le programmeur se doit de savoir effectuer des tâches minimalistes, telles les calculs de convergence,
la génération aléatoire, le tri de données, etc.
Considérez donc le cours suivant comme un guide d’initiation à quelques problèmes
fondamentaux de la programmation. Il n’est certainement pas exhaustif, et n’en a pas la moindre
prétention, mais très certainement il vous sera plus qu’utile. Les diverses notions dont nous
traiterons par la suite seront abordées de la façon le plus simple possible, et l’élaboration des codes
sources en Turbo-Pascal suivra la même logique.
Il est possible que des erreurs se soient glissées dans le présent document, bien que j’aie fait
tout mon possible pour que cela ne soit pas. « Errare Humanum est », dit-on; il vous appartient donc
de me soumettre lesdites erreurs, afin que je puisse les corriger promptement.
Vous vous interrogerez certainement sur la façon d’aborder ce document…A priori, aucune.
Les différents problèmes dont je traite sont catégorisés, suivant leur degré de complexité. Il va de soi
que vous ne devrez par parcourir ce document de bout en bout, comme vous liriez un roman, mais
plutôt en cherchant ce qui vous intéresse via le sommaire des sujets traités. Notez bien que chaque
nouveau problème sera abordé de la manière suivante :
Le problème posé
Sa résolution progressive en langage courant puis en langage Pascal.
La plus grave des erreurs serait de considérer ce document comme un cours d’initiation au
Turbo-Pascal. Il n’en est pas un. En effet, je suppose ici que vous connaissez déjà (et plutôt bien) la
manipulation du langage Pascal. La base est de savoir au moins concevoir un programme, définir et
employer une fonction, une procédure, utiliser les structures conditionnelles, itératives, répétitives,
savoir compiler et exécuter un programme.
L’essentiel ayant été dit, il ne reste plus à vous souhaiter que ce document vous sera
pleinement utile. Faites-en bon usage !
R.Y.
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
4
I. Calculs et opérations numériques
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
5
Dans cette première partie, afin de nous familiariser avec les concepts élémentaires de la
programmation, nous allons tenter de résoudre des problèmes simples. Il s’agira pour la plupart des
cas de formules de calcul déjà à mettre sus code. Pour d’autres cas, vous apprendrez (en douceur)
quelques algorithmes de calcul très simples qui pourront vous être utiles plus tard.
Pour cette partie, vous pourrez bien entendu lire simplement l’énoncé, et tenter de le résoudre,
avant de lire la solution proposé. Je vous le recommande vivement, car la plupart des 12 problèmes
qui vont suivre sont à votre portée.
Sur ce, bon code !
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
6
1. Somme d’entiers entre deux bornes définies
Ecrire un programme qui calcule et affiche la somme des nombres entiers de 1 à 10.
Résolution
Il s’agit probablement de l’un des problèmes les plus triviaux, mais qui à l’intérêt de former
utilement à la manipulation des structures itératives.
L’objectif est de concevoir un programme qui calcule la quantité :
L’on pourrait probablement penser à un programme de ce genre :
program calcul_somme; uses wincrt; var somme:integer; begin somme := 1+2+3+4+5+6+7+8+9+10; writeln(somme); end.
Ce programme donnerait certes la bonne réponse. Mais, que lui reprocher ? D’être à la limite
un programme…« stupide ».
Imaginez un instant qu’il nous avait été demandé de calculer la somme des entiers de 1 à 100
plutôt, et que nous voudrions utiliser la même méthode…On devrait donc s’échiner à modifier la
ligne somme := 1+2+3+4+5+67+8+9+10; en somme = 1+2+3+4… et continuer la saisie jusqu’à 100…Ce
qui est impensable en programmation.
Notez une chose, la programmation relève souvent de la paresse… Toujours chercher donc le
chemin le plus court.
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
7
Il suffit de constater que nous voulons calculer ∑ .Un structure itérative ferait très bien
l’affaire :
program calcul_somme; uses wincrt; var somme,i:integer; begin somme:=0; for i:=1 to 10 do somme:=somme+i; writeln(somme); end.
Figure 1. Résultat de l'exécution
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
8
2. Somme d’entiers de 1 à n
Ecrire un programme qui reçoit de son utilisateur un nombre entier n et qui calcule et affiche
la somme des entiers de 1 à n.
Résolution
Ce problème devient encore plus simple une fois que l’on a traité l’Exercice I de cette même partie.
Nous voulons calculer la quantité : ∑ . Sauf qu’ici, léger détail qui a son importance, la borne n
n’est pas définie dans notre programme, mais doit être entrée par l’utilisateur.
Nous aurons donc besoin de :
Récupérer la borne n
Calculer et afficher la somme des entiers de 1 à n avec une structure itérative (une boucle
for).
Ce qui nous conduit à la solution suivante :
program calcul_somme; uses wincrt; var somme,i,n:integer; begin somme:=0; writeln('Entrez la borne n'); read(n); for i:=1 to n do somme:=somme+i; writeln('somme = ',somme); end.
Figure 2. Exemple avec n=12
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
9
3. Calcul d’une factorielle
Concevoir un programme qui calcule la factorielle d’un nombre entier n défini par l’utilisateur.
Résolution
Nous voici sans nul doute en présence d’un problème plus complexe que ce que nous venons de voir jusqu’alors. Nous savons tous que la factorielle d’un nombre se définit comme étant le produit des nombres inférieurs ou égal à ce nombre :
( ) ( ) ∏
Nous allons donc utiliser une structure itérative pour calculer le produit des nombres de 1 à n, avec n étant reçu d’un utilisateur de notre programme :
program calcul_factorielle; uses wincrt; var factorielle,n,i:integer; begin factorielle:=1; writeln('Entrez la borne n'); read(n); for i:=1 to n do factorielle:=factorielle*i; writeln('factorielle = ',factorielle); end. Et c’est tout ! Essayez d’entrer les nombres suivants et de comparer les résultats fournis par le programme avec les résultats exact :
0 ! = 1 (convention mathématique, rappelez-vous-en !)
1 ! = 1
2 ! = 2x1 = 2
3 ! = 3x2x1 = 6
4 ! = 4x2x1 = 24
5 ! = 5x4x3x2x1 = 120
6 !=6x5x4x3x2x1 = 720
7 !=7x6x5x4x3x2X1 = 5040 Pour aller plus loin …
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
10
Jusqu’ici, le programme semblait fiable. Essayez cependant le calcul de factorielle avec 8.
8 ! = 8x7x6x5x4x3x2x1 = 40320. Tandis que programme vous affichera (tenez-vous bien) : -25216 ! Où se trouve le problème ?
Et bien, il réside dans la définition de nos types de variables. Nous avons déclaré au départ la
variable factorielle (censée contenir le résultat final) en type integer. Oui, il est vrai que factorielle est toujours un nombre entier, mais le problème est le suivant :
Le type integer, (étant stocké sur un espace de 2 octets, donc sur 16 bits, dont 1 de signe, mais ça vous vous en fichez complètement…) ne peut contenir QUE DES NOMBRES ENTIERS COMPRIS ENTRE
Donc, puisque 8 ! = 40320, 8! ne peut pas rentrer dans un integer, et le programme affiche donc n’importe quoi…
Remédier au problème est simple…Il suffit de déclarer factorielle en un type différent. Par
exemple longint. C’est le plus grand conteneur d’entiers existant en Pascal. Il peut contenir des nombres compris entre
. Mais par exemple, vous serez limité à 12 !
Voici donc une amélioration possible de votre programme :
program calcul_factorielle; uses wincrt; var factorielle:longint; n,i:integer; begin factorielle:=1; writeln('Entrez la borne n (inférieure ou égale à 12 svp !)'); read(n); for i:=1 to n do factorielle:=factorielle*i; writeln('factorielle = ',factorielle); end.
Pour aller encore plus loin…
Figure 3. Exemple de calcul avec n=12
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
11
Voilà, nous avons donc conçu un programme qui sait calculer la factorielle d’un nombre. Du
moins, pour un nombre positif entier inférieur à 12. Il se peut que dans certains cas, nous ayons
besoin de calculer la factorielle d’un nombre pour l’employer dans un autre calcul plus complexe. Il
serait alors judicieux de transformer le précédent programme en une fonction qui retourne la
factorielle d’un nombre n pris en paramètre. L’exemple concret :
program calcul_factorielle; uses wincrt; {Fonction calculant la factorielle de n} function factorielle(n:integer):longint; var i:integer; produit:longint; begin produit:=1; for i:=1 to n do produit:=produit*i; factorielle:=produit; end; {Début du programme principal} var n:integer; begin writeln('Entrez la borne n (inférieure ou égale à 12 svp !)'); read(n); writeln('factorielle = ',factorielle(n)); end.
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
12
4. Calcul de
Ecrire une fonction en Pascal qui retourne un nombre x élevé à une puissance entière y. Les valeurs x et y seront définies par l’utilisateur du programme.
Résolution
Voilà une fois de plus le genre d’exercice qui se résout très simplement une fois que nous
avons défini ce que nous cherchons. Ici, c’est calculer : .
Clarifions auparavant les choses. Ici, l’énoncé nous simplifie la vie en nous imposant y étant un nombre entier ! Cependant, aucune précision sur la nature de x, qui peut être un réel !
Nous pouvons donc conclure très rapidement : x élevé à la puissance y, c’est le produit de x par lui-même y fois ! Utilisons donc la boucle for, qui est parfaite dans ce cas. program calcul_puissance; uses wincrt; var puissance,x:real; y,i:integer; begin puissance:=1; writeln('Entrez le nombre x:'); readln(x); writeln('Entrez la puissance y:'); readln(y); for i:=1 to y do puissance:=puissance*x; writeln('puissance = ',puissance); end.
Figure 4. Calcul de 4^3
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
13
Voilà donc le programme général. L’énoncé demande toutefois d’en faire une fonction qui retournerait la factorielle. Qu’à cela tienne, une légère modification le permet. program calcul_puissance; uses wincrt; {Fonction renvoyant x^y} function puissance(x:real;y:integer):real; var p:real; i:integer; begin p:=1; for i:=1 to y do p:=p*x; puissance:=p; end; {Reste du programme principal} var x:real; y:integer; begin writeln('Entrez le nombre x:'); readln(x); writeln('Entrez la puissance y:'); readln(y); writeln('puissance = ',puissance(x,y)); end.
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
14
5. Les nombres parfaits
« Un nombre entier est dit parfait s’il est égal à la somme de ses diviseurs stricts ». Ecrire un
programme qui cherche et affiche les 4 premiers nombres parfaits.
Résolution
Cet exercice est assez simple puisqu’il s’agit essentiellement d’identifier les diviseurs stricts
d’un nombre entier positifs. L’opérateur modulo va nous être d’un grand recours.
Le modulo d’une division de A par B est le reste de la division entière de A par B. Si vous le
saviez déjà, prenez cela comme un rappel…
Donc 5 modulo 3 = 2, car 5/3 = 1 et reste 2. C’est tout simple.
Remarquons que si A modulo B = 0, alors A est multiple de B ou B est diviseur de A, prenez ça
comme vous le voulez. Vérifions-le illico presto.
6/3 = 2 reste 0..Donc 3 est diviseur de 6… on peut aussi dire 6 est multiple de 3.
Cela va peut-être vous étonner, mais l’exercice est pratiquement résolu ! La démarche que
nous allons employer est la suivante :
Etape 1 : Fixer la variable comptant les nombres parfaits trouvés à 0. Etape 2: Commencer par un nombre (1 de préférence). Etape 3 : Fixer la somme de ses diviseurs à 0. Etape 4 : Calculer le modulo de ce nombre par tous les entiers strictement inférieurs à ce nombre. Si pour une division, le modulo est nul, on rajoute le diviseur à la somme des diviseurs. Etape 5 : Une fois la somme des diviseurs trouvés, on compare le nombre à la somme des diviseurs. S’ils sont égaux, on affiche le nombre, et on augmente de 1 la variable comptant de nombres parfaits trouvés. Etape 6 : On passe au nombre suivant et on répète l’étape 3, jusqu’à ce que la variable comptant les nombres trouvés soit égale à 4.
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
15
Voici le programme correspondant : program nombres_parfaits; uses wincrt; var nombre_trouves,somme_diviseurs,nombre_actuel,i:integer; begin nombre_trouves:=0; nombre_actuel:=1; repeat somme_diviseurs:=0; for i:=1 to (nombre_actuel-1) do if ((nombre_actuel mod i)=0) then somme_diviseurs:=somme_diviseurs+i; if (nombre_actuel = somme_diviseurs) then begin writeln(nombre_actuel); nombre_trouves:=nombre_trouves+1; end; nombre_actuel:=nombre_actuel+1; until (nombre_trouves=4); end.
Figure 5 : Nombres parfaits
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
16
6. PGCD de deux entiers A et B
Construire une fonction qui calcule le PGCD de deux nombres entiers a et b qui sont définis par l’utilisateur.
Résolution
Pour la résolution d’un tel programme, il ne serait pas superflu de commencer par quelques rappels mathématiques.
Le PGCD se définit comme étant le Plus Grand Commun Diviseur de deux entiers. Pour un
couple de nombres entier-décimal, ou un couple décimal-décimal, le PGCD n’existe pas. Bien entendu, si l’un des nombres est égal à zéro, leur PGCD est alors nul…
Nous avons appris dans les classes antérieures à calculer le PGCD à partir de la
décomposition en nombres premiers. Par exemple pour le calcul du PGCD(20,10) ; ( )
Effectivement le plus grand diviseur commun à 10 et à 20 est bien 10…
Autre exemple, pour le PGCD(38,12) :
( )
Nous n’allons cependant pas appliquer ici ce procédé de calcul qui est assez long, mais utiliser des algorithmes de calcul rapide du PGCD. Je vous offre ici principalement deux de ces méthodes :
La méthode d’Euclide
La méthode Egyptienne
Méthode d’Euclide
Elle est d’une simplicité extrême. Voici son principe : Soient deux entiers A et B tels que A soit supérieur à B : Soit un nombre R
REPETER LES OPERATIONS SUIVANTES Calculer R = modulo de A/B (c’est-à-dire le reste de la division entière de A par B) A prend la valeur de B B prend la valeur de R JUSQU'A CE QUE R SOIT EGAL A ZERO
PGCD = A
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
17
L’élève aime bien avoir l’illustration des propos théoriques. Soit, voici un exemple
d’application. Nous cherchons le PGCD (12,15) .
Nous prenons donc A=15 et B = 12 (car A doit être supérieur à B) A/B = 15/12 = 1 et reste 3. Donc R=3. A = 12 (l’ancienne valeur de B) et B = 3 (la valeur de R)
Comme R ne vaut pas 0, reprenons. A/B = 12/3 = 4 et reste 0. Donc R = 0. A=3 (la précédente valeur de B) et B = 0 (la précédente valeur de R).
R vaut 0, On s’arrête. Le PGCD est A, soit 3. Nous allons mettre en application ce procédé, mais avec toutefois quelques optimisations :
Nous remarquons tout de suite un léger handicap. Cette façon de calculer le PGCD ne marche qu’avec un nombre A supérieur à un nombre B. Nous devrons nous charger nous-mêmes de permuter A et B si ce n’est pas le cas.
De plus nous pouvons faire certains constats sur le calcul du PGCD.
Si A ou B est nul, leur PGCD est automatiquement nul.
Si A = B alors leur PGCD (A,B ) = A = B
Si A, étant plus grand que B, est multiple de B, alors PGCD(A,B ) = B
Ces constatations sont importantes dans la mesure où elles peuvent nous permettre
d’accélérer le calcul du PGCD. Voici donc comment nous composerons notre fonction
Fonction PGCD(entiers A et B) : retourne un entier Soit R un entier DEBUT.FONCTION S’assurer que A > B auquel cas, les permuter en s’appuyant sur R. SI (A=0) ou (B=0) alors STOP. PGCD =0 SINON SI (A=B) alors STOP.PGCD =A SINON SI (A est multiple de B) ALORS STOP.PGCD =B SINON REPETER R = RESTE de A/B A=B B=R JUSQU'A CE QUE (R=0) PGCD = A FIN.FONCTION
Et voici un programme dans lequel cette fonction est définie et appelée par le programme principal :
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
18
function pgcd(a,b:integer):integer; var r:integer; begin if (a<b) then begin r:=a; a:=b; b:=r; end; if (a=0) or (b=0) then pgcd:=0 else if (a=b) then pgcd:=a else if ((a mod b)=0) then pgcd:=b else begin repeat r:=a mod b; a:=b; b:=r; until (r=0); pgcd:=a; end; end;
Méthode Egyptienne
Cette seconde méthode est tout aussi aisée à appliquer. Voici son principe :
Soient A et B deux entiers REPETER LES OPERATIONS SUIVANTES SI (A>B) ALORS A = A-B SINON B = B-A JUSQU'à CE QUE A SOIT EGAL à B PGCD = A ou B Nous allons construire donc notre fonction sur le principe suivant :
Fonction EPGCD (entiers A, B) : retourne un entier ; DEBUT.FONCTION SI (A=0) ou (B=0) alors STOP.PGCD = 0 SINON TANT QUE (A Différent de B) SI (A>B) alors A= A-B SINON B= B-A FIN TANT.QUE PGCD = A FIN.FONCTION
Et voici le code associé :
function Epgcd(a,b:integer):integer; begin
Figure 6. Calcul PGCD (0,4)
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
19
if (a=0) or (b=0) then Epgcd:=0 else while (a<>b) do if (a>b) then a:=a-b else b:=b-a; Epgcd:=a; end;
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
20
7. PPCM de deux entiers A et B
Concevoir une fonction qui calcule le PPCM de deux nombres entiers a et b. Ecrire un programme qui emploie cette fonction. Les nombres a et b seront définis par un utilisateur.
Résolution
Ce problème est une suite logique du précédent. Ici encore, pour obtenir le PPCM (Plus Petit Commun Multiple) de deux nombres, il faut passer par leur décomposition en facteurs premiers. Cependant, nous allons encore préférer un autre principe mathématique, qui nous sauvera la mise :
Soient A et B deux entiers positifs :
Si A=0 ou B=0 alors PPCM (A, B) = 0
Si A et B simultanément différents de 0, alors ( )
( )
Difficile de faire plus simple...Le problème est ramené donc à un simple calcul de PGCD,
aspect qui traité à l’Exercice VI. Nous allons donc réemployer la fonction de calcul de PGCD par la méthode Egyptienne (c’est la plus courte à écrire, pardi !) pour construire celle du calcul du PPCM. Ensuite l’associer à un programme principal qui demandera deux entiers a et b à l’utilisateur et affichera leur PPCM en appelant la fonction de calcul du PPCM, que nous aurons auparavant définie (vous me suivez toujours… ?). program calcul_ppcm; uses wincrt; {Fonction renvoyant le pgcd de deux entiers a et b} function Epgcd(a,b:integer):integer; begin if (a=0) or (b=0) then Epgcd:=0 else while (a<>b) do if (a>b) then a:=a-b else b:=b-a; Epgcd:=a; end; {Fonction renvoyant le ppcm de deux entiers a et b} function ppcm(a,b:integer):integer; begin if (a=0) or (b=0) then ppcm:=0 else ppcm:=trunc((a*b)/Epgcd(a,b)); end; var a,b:integer; begin writeln('Entrez le nombre a:'); readln(a); writeln('Entrez le nombre b:'); readln(b); writeln('ppcm = ',ppcm(a,b)); end.
Figure 7. Calcul PPCM(12,22)
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
21
8. Combinaisons de p-uplets dans un ensemble n-uplets.
Ecrire une fonction qui calcule les combinaisons de p-éléments dans un ensemble fini de n-éléments.
Résolution
C’est un exercice simple une fois que le problème général est dégagé. En effet, les mathématiques nous enseignent que :
( )
Imaginons que nous sachions calculer la factorielle d’un nombre. La fonction que l’on nous demande ici devient simple à concevoir : Fonction combinaison (entiers n, p) : renvoie un entier ; DEBUT.FONCTION Combinaison = factorielle(n)/[factorielle(p)*factorielle(n-p)] FIN.FONCTION Le calcul de la factorielle d’un nombre est déjà traité à l’Exercice III. Nous allons simplement réutiliser le code de la fonction factorielle qui y est défini pour arriver à nos fins. program calcul_combinaison; uses wincrt; {Fonction renvoyant la factorielle de n} function factorielle(n:integer):longint; var i:integer; produit:longint; begin produit:=1; for i:=1 to n do produit:=produit*i; factorielle:=produit; end; {Fonction renvoyant les combinaisons de p dans n} function combinaison(n,p:integer):integer; begin combinaison:=trunc(factorielle(n)/(factorielle(p)*factorielle(n-p))); end; var n,p:integer; begin writeln('Entrez le nombre n:'); readln(n); writeln('Entrez le nombre p:'); readln(p); writeln('combinaison(p,n) = ',combinaison(n,p)); end.
Figure 8. Calcul des Comb. de 4 dans 10
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
22
9. Test de primalité d’un entier positif N
Ecrire une fonction qui prend en paramètre un entier n et qui renvoie :
Vrai si le nombre en question est un nombre premier
Faux le cas échéant.
La fonction sera nommée Est_Premier(). L’utiliser dans un programme.
Résolution
Ne pas paniquer devant un tel énoncé. C’est en effet beaucoup plus simple qu’il n’y paraît.
La question à se poser, c’est : « Qu’est-ce qu’un nombre premier ? ».
La réponse : « Un nombre est premier s’il est seulement divisible par 1 et par lui-même ».
Cependant il existe une convention mathématique selon laquelle 1 n’est pas un nombre premier.
Pour arriver à nos fins, nous allons nous baser sur quatre postulats :
1 n’est pas premier. C’est une convention.
Un nombre entier est toujours divisible par 1. C’est une évidence. Aucun besoin donc de
chercher à le vérifier.
Un nombre entier est toujours divisible par lui-même. C’est encore une évidence.
Si le reste du rapport d’un entier A par un entier B inférieur est nul (A modulo B = 0) alors A
est multiple de B (c’est une fois de plus une évidence).
Pour savoir si un nombre N est premier, il suffit donc de le diviser successivement par tous
les nombres entiers strictement supérieurs à 1 et qui lui sont strictement inférieurs. Si le reste d’une
de ces divisions est nul, alors le nombre N possède un sous-multiple, est n’est donc pas premier.
Sinon, bingo ! N est premier.
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
23
program test_de_primalite; uses wincrt; function Est_premier(n:integer):boolean; var i:integer; divisible:boolean; begin if (n=1) then Est_premier:=false else begin divisible:=false; for i:=2 to (n-1) do if ((n mod i)=0) then divisible:=true; if (divisible) then Est_premier:=false else Est_premier:=true; end; end; var n:integer; begin writeln('Entrez un nombre n'); read(n); writeln('Entrez le nombre n:'); writeln(n,' est-il premier ? ',Est_premier(n)); end.
Figure 9. Test de primalité de 7
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
24
10. Conjecture de Goldbach
Un théorème qui ne possède pas de démonstration s’appelle une conjecture. L’objectif est de construire un programme qui illustre la conjecture de Goldbach.
Christian Goldbach fût un mathématicien russe qui a émis l’hypothèse suivante en 1742 : « Tout nombre pair est la somme de deux nombres premiers ».
Construire un programme qui illustre cette conjecture pour un nombre entier défini par un utilisateur.
Résolution
Voilà un programme qui est enrichissant, du point de vue culture générale. Nous découvrons
la conjecture de Goldbach… Comment le résoudre ? En le décomposant en sous-tâches. Nous partons donc avec un nombre pair N.
Dans un premier temps, nous allons rechercher tous les couples de valeurs (A, B) tels que N=A+B. Par exemple, pour N = 8, nous retiendrons les couples : (1,7) , (2,6) , (3,5) , (4,4).
Ensuite, pour chaque couple (A, B) généré, nous vérifierons si A et B sont simultanément premiers. Une fonction permettant de savoir si un nombre est premier a été déjà définie à l’Exercice VIII. Nous allons ici réutiliser cette fonction ici.
program conjecture_goldbach; uses wincrt; {Fonction effectuant le test de primalité d’un entier n} function Est_premier(n:integer):boolean; var i:integer; divisible:boolean; begin if (n=1) then Est_premier:=false else begin divisible:=false; for i:=2 to (n-1) do if ((n mod i)=0) then divisible:=true; if (divisible) then Est_premier:=false else Est_premier:=true; end; end; {Programme principal} var n,a,b,i:integer; begin writeln('Entrez un nombre n'); read(n); if ((n mod 2)<>0) then writeln(n,' n''est par pair!') else for i:=1 to (n div 2) do begin a:=i; b:=n-i; if Est_premier(a) and Est_premier(b) then writeln(n,' = ',a,' + ',b); end; end.
Figure 7. Conjecture de GoldBach sur le nombre 100
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
25
11. Définir une fonction polynomiale de degré N Concevoir un programme un programme permettant de calculer la valeur en un point réel x0
de n’importe qu’elle fonction polynomiale f(x). Le degré de la fonction, ses coefficients ainsi que le paramètre x0 seront définis par l’utilisateur. Notez que le paramètre x0 peut être un réel. Le résultat f(x0) sera arrondi à 2 décimales à l’affichage.
Résolution Commençons par définir ce à quoi nous voulons aboutir. Ici, il s’agit de calculer f(x0) avec f étant une fonction polynomiale, de degré n. Qu’est- ce -qu’une fonction polynomiale ? Simplement une fonction de R vers R, qui à tout réel x associe la quantité :
( ) Nous remarquons tout de suite une chose : La fonction est entièrement définie une fois que nous connaissons les coefficients . De plus, chaque monôme suit la même construction. Un coefficient , multiplié par le réel x élevé à la puissance i…. D’où la forme condensée :
( ) ∑
Pour arriver à un programme fonctionnel, il faudrait déjà que nous sachions programmer le calcul d’un réel x élevé à la puissance i. Problème déjà traité à l’Exercice IV. Fort de cet atout, nous allons concevoir notre programme de cette manière. Soient : les réels A, x0, F
Et les entiers N et I Début.Programme Initialiser F à 0. Récupérer dans x0 la valeur en laquelle il faut calculer f. Récupérer dans N le dégré de la fonction polynomiale
Pour i allant du dégré N à 0 Récupérer dans A le coefficient .
Calculer , rajouter à F Fin.Pour
Afficher F Fin.Programme Toutefois, attention! Ceci n’est qu’un algorithme général, qui vous présente le squelette final
du programme, et son fonctionnement. En pratique, il est impossible en Pascal de calculer de façon
brute x0 à la puissance i…comme je l’explique plus haut. Cette ligne devra donc être remplacée par
l’appel à une fonction qui fera ce travail. Nous n’aurons qu’à recopier le code de la fonction
puissance() qui a fait l’objet de l’Exercice IV.
Dernier détail, l’énoncé nous demande l’affichage de la solution avec 2 décimales. Pour cela il
suffit de rajouter deux paramètres sur le réel f lorsqu’on l’affiche :
( )
Dans notre cas, nous ferons : ( )
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
26
Le programme final : program calcul_f(x0); uses wincrt; {Fonction renvoyant x à la puissance y} function puissance(x:real;y:integer):real; var p:real; i:integer; begin p:=1; for i:=1 to y do p:=p*x; puissance:=p; end; {programme principal} var a,n,i:integer; f,x0:real; begin writeln('Entrez le point x0'); readln(x0); writeln('Entrez le degré'); readln(n); f:=0; for i:=n downto 0 do begin writeln('Entrez le coefficient de x^',i,':'); readln(a); f:=f+(a*puissance(x0,i)); end; writeln('f(',x0:0:2,') = ',f:0:2); end.
Figure 8. Calcul de f(-3) avec f(x) = x^2
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
27
12. Les nombres d’Armstrong
« Un nombre d’Armstrong est un nombre entier qui est égal à la somme des cubes des chiffres
dont il se compose ». Sachant qu’il existe 4 de ces nombres compris entre 100 et 999, écrire un
programme qui cherche et affiche ces 4 nombres.
Résolution
Nous cherchons donc 4 nombres compris entre 100 et 999. Ce sont donc obligatoirement des
nombres à 3 chiffres. Un chiffre des centaines, un chiffre des dizaines et un dernier pour les unités. Si
le nombre est abc alors :
Le nombre abc sera dit nombre d’Armstrong si en notant ce nombre abc, on a :
Pour identifier de tels nombres, il suffit de faire varier simultanément trois chiffres a, b et c :
Le premier chiffre a, utilisé pour identifier le chiffre des centaines, variera entre 1 et 9.
Le 2ème chiffre b, utilisé pour identifier le chiffre des dizaines, variera entre 0 et 9.
Le 3ème chiffre c, utilisé pour identifier le chiffre des unités, variera entre 0 et 9.
Pour chaque nombre abc formé, on fera le test suivant :
Si alors on affichera le nombre abc.
program nombres_amrstrong; uses wincrt; var a,b,c,somme_cubes,nombre:integer; begin for a:=1 to 9 do for b:=0 to 9 do for c:=0 to 9 do begin somme_cubes:=(a*a*a)+(b*b*b)+(c*c*c); nombre:=(100*a)+(10*b)+c; if (somme_cubes=nombre) then writeln(nombre); end; end.
Figure 9. Les 4 nombres d'Armstrong
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
28
II. Itérations, Convergence, Conversions, Approximations,
simulations de problèmes
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
29
Dans cette partie, les problèmes abordés seront quelques peu différents de ceux traités jusqu’alors. Il
ne s’agira plus de calculs simples, mais de véritables « sujets de recherche ». La démarche adoptée
est la suivante :
La présentation du problème posé
La méthode de résolution détaillée (à l’aide schémas illustratifs)
L’implémentation de l’algorithme dégagé
Par conséquent, à titre de conseil, il vous faudra avoir bien maitrisé les quelques concepts de
la première partie, et être à l’aise dans la manipulation du langage Turbo Pascal avant d’aborder la
suite.
Bon code !
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
30
1. Approximation de la « divine proportion ».
L’objectif principal de cet exercice est d’approcher une grandeur célèbre, appelée « nombre
d’or » ou encore la « divine proportion ».
Soit un segment AB, et un point C sur ce segment.
Ce segment doit être tel que le rapport de la plus grande partie de AB sur la plus petite partie
de AB est toujours égal au segment AB sur sa plus grande partie. Autrement dit, ici :
En posant AC=x et CB = 1, on a :
La seule solution positive de cette équation est notée et vaut exactement √
. Le
nombre est appelé « nombre d’or ».
Il existe deux manières d’approcher le nombre d’or par critère de convergence :
1ère méthode :
(
(
)
)
2ème méthode : √
√ √ √ √ √
Construire deux procédures (une procédure pour chaque méthode) calculant le nombre d’or. Ces
procédures prendront un unique paramètre epsilon, correspondant à la précision de calcul, et
devront :
Afficher le nombre d’or à epsilon près une fois trouvé. Renvoyer aussi le nombres d’itérations qu’il a
fallu effectuer pour trouver le nombre d’or à epsilon près
Indication : Pour effectuer un calcul à epsilon près, il suffit de répéter le calcul jusqu’à ce que
deux résultats consécutifs soient proches de moins de epsilon.
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
31
Résolution
Nous allons d’abord chercher à construire la première procédure de calcul du nombre d’Or.
Elle prend en paramètre un réel, qui est la précision epsilon. Elle renvoie le rang auquel le nombre
d’or à epsilon près est trouvé.
Le principe est simple. Nous partons avec deux variables phi1 et phi2.
Etape 1 : On fixe phi1 = 1. On a effectué 0 itérations jusqu’alors.
Les instructions suivantes seront répétées jusqu’à ce que | | :
Etape 2 : On fixe phi2 = phi1
Etape 3 : On calcule phi1 = 1+ (1/phi1), on augmente de 1 le nombre d’itérations
Etape 4 : On compare le nouveau phi1 à phi2…S’ils sont distants de moins de epsilon, la
précision est atteinte, sinon, on reprend à l’étape 2.
procedure nombredor(epsilon:real); var rang:integer; phi1,phi2:real; begin phi1:=1; rang:=0; repeat phi2:=phi1; phi1:=1+(1/phi1); {Ligne explicitant le processus iteratif} rang:=rang+1; until (abs(phi1-phi2)<epsilon); writeln('nombre d''or: ',phi1); writeln('nombre d''itérations nécessaires : ',rang); end; La deuxième procédure sera construite de façon similaire. Je vous épargne les longs discours: procedure nombredor2(epsilon:real); var rang:integer; phi1,phi2:real; begin phi1:=1; rang:=0; repeat phi2:=phi1; phi1:=sqrt(1+phi1); {Ligne explicitant le processus itératif} rang:=rang+1; until (abs(phi1-phi2)<epsilon); writeln('nombre d''or: ',phi1); writeln('nombre d''itérations nécessaires : ',rang); end;
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
32
2. Simulation de lancer d’une pièce de monnaie
On désire effectuer une simulation de lancer d’une pièce de monnaie. L’objectif est de
construire un programme simulant 100 jets de pièce de monnaie à l’issue duquel il affiche :
Le nombre d’occurrences de « Pile ».
Le nombre d’occurrences de « Face ».
Pour simuler le jet d’une pièce de monnaie, le programme devra choisir un nombre au hasard
entre 1 et 100. Si le nombre est strictement inférieur à 50, cela correspond à l’issue « Pile ».S’il est
strictement supérieur à 50, cela correspond à l’issue « Face ». Mais si le nombre pris au hasard est
égal à 50, en générer un nouveau.
Résolution
C’est un exercice facile à résoudre dans son principe général. Il nous aidera à comprendre le
fonctionnement de la génération aléatoire, qui est un aspect de la programmation à connaitre
nécessairement.
Souvent, dans certains programmes, l’on a besoin de générer des valeurs « au hasard »,
avant de les traiter par des instructions diverses. Cela est possible grâce à la fonction random(), qui
est commune à quasiment tous les langages de programmation.
En exécutant ainsi une ligne telle que : ( ), la variable y contient un entier
compris entre 0 et 10…mais on ne sait pas lequel. A moins d’afficher le contenu de cette variable.
Pour plus de détails sur l’emploi de la fonction random(), vous pouvez vous référer à la
documentation de Borland Pascal.
Pour revenir au problème qui nous est soumis, une tentative de réponse serait un
programme répétant 100 fois les étapes suivantes dans ce genre :
Générer un nombre aléatoire entre 0 et 100.
Si ce nombre est inférieur à 50, alors on le compte pour Pile. S’il est supérieur à 50, on le
compte pour « Face ». S’il est égal à 50, on en génère un nouveau qui soit différent de 50.
La solution est disponible plus bas. Cependant, vous noterez que j’emploie en début de
programme une procédure, Randomize ; Son utilité ?
Pour comprendre l’utilité de cette procédure, il faut savoir que pour une machine à calcul,
générer des nombres aléatoires relève d’un parcours du combattant. Car il faut que cela soit fait de
manière à ce qu’il n’y n’apparaisse pas à l’observation de la série de valeurs générés une loi
d’évolution apparente…La plupart des systèmes de génération de valeurs aléatoires possèdent une
série prédéfinie de valeurs, dans laquelle ils puisent des valeurs et les renvoient lorsque l’on
demande un de ces nombres…Résultat, si un programme utilisant la fonction random() est exécuté
plusieurs fois de suite, les mêmes valeurs seront disponibles, ce qui ôte tout effet de « hasard ».
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
33
La procédure Randomize() donne l’ordre au système de recalculer toutes les valeurs de la
liste de nombres pseudo-aléatoires prédéfinis en se basant sur une graine (encore appelée seed) qui
peut être une valeur choisie arbitrairement ou qui est généralement calculée à partir de l’heure
système courante…Résultat, votre programme a l’air plus réaliste, car plus « hasardeux ».
Bon, si vous n’avez pas compris, pas de souci…Dites-vous que s’il y a la procédure
Randomize(), mieux c’est quand vous employez Random().
Le programme final :
program aleatoire; uses wincrt; var n_pile,n_face,n_total,rand:integer; begin Randomize; n_pile:=0; n_face:=0; n_total:= 0; repeat rand:=random(100); if (rand<50) then n_pile:=n_pile+1 else if (rand>50) then n_face:=n_face+1 else repeat rand:=random(100); until (rand<>50); n_total:=n_total+1; until (n_total>=100); writeln('Nombre Piles : ',n_pile); writeln('Nombre Faces: ',n_face); end.
Figure 10. Simulation de lancer de pièce de monnaie
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
34
3. Approximation de Pi par la méthode statistique
est un nombre irrationnel dont le nombre de décimales est infini. On désire construire un
programme qui converge vers la véritable valeur de Pi en s’appuyant sur la théorie des grands
nombres. Voici le principe :
Soit a un réel positif. Soit un carré de côté 2a, et un cercle inscrit dans le carré de rayon a.
Laissons tomber dans le carré une goutte d’eau. Quelle est la probabilité que cette goutte
tombe dans le cercle ?
La réponse serait :
( )
La loi des grands nombres appliquée à cette situation nous permet de dire : « Si nous laissons
tomber non pas une, mais des milliards de gouttes dans le carré, et que nous faisons le rapport des
gouttes qui sont tombées dans le cercle, sur les total des gouttes que nous avons laissées chuter dans
le carré, nous avons une excellente approximation de
».
Il suffit donc de multiplier par 4 cette approximation pour avoir une toute aussi excellente
approximation de Pi….
Concevoir un programme qui illustre cette hypothèse. Au début du programme, l’utilisateur
devra préciser le nombre de gouttes qu’il souhaite employer pour son approximation de Pi. Il va sans
dire que plus grand sera ce nombre, meilleure sera l’évaluation de Pi. A chaque itération devra être
affiché :
Le nombre de gouttes dans le cercle
Le nombre de gouttes générées au total
L’approximation courante : la valeur approchée de Pi obtenue par le programme devra être
affichée à chaque itération et avec 10 décimales.
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
35
Résolution
Nous allons ici définir un certain nombre de variables de type entier.
nGen : il s’agit du nombre total de points à générer.
inC : cette variable nous servira à dénombrer les points générés qui seront dans le cercle.
outC : nous servira à dénombrer les points générés hors du cercle.
Il est clair que nous devrons avoir la relation : nGen = inC + outC en fin d’expérience.
Voici l’algorithme que nous allons mettre sous code :
Demander à l’utilisateur le nombre de points qu’il souhaite générer et stocker cette valeur
dans nGen.
Initialiser les variables inC et outC à 0.
Répéter ceci :
Retrancher 1 à nGen.
Générer 2 nombres au hasard entre 0 et 1. Ces deux nombres constitueront pour nous les
coordonnées x et y d’un point.
Vérifier si ce point généré est dans le cercle de centre (0.5, 0.5) et de rayon 0.5. Si oui, on
rajoute 1 à inC. Sinon, on rajoute 1 à outC.
Afficher les informations requises inC, nGen, et l’approximation de PI).
Jusqu’à ce que nGen atteigne 0 (c’est - à - dire que nGen points ont été générés).
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
36
Le programme final :
program Evalpi; uses wincrt; var inC,outC,nGen:integer; randX,randY:double; begin Randomize; write('Nombre de generations aleatoires : '); readln(nGen); inC:=0; outC:=0; repeat randX:=random(100)/100; randY:=random(100)/100; nGen:=nGen-1; if ((randX-0.5)*(randX-0.5)+(randY-0.5)*(randY-0.5)<0.5*0.5) Then inC:= inC+1 else outC:=outC+1; writeln('Nbre Points dans le cercle: ',inC,' Total : ',(inC+outC)); writeln('Approximation courante : ',(inC/(outC+inC))*4); writeln; until (nGen<=0); end. Nota : Il est possible que le code fourni ne compile pas. Vous pourrez recevoir une erreur de ce type :
« Must be in 8087 Mode to compile this ».
Ceci signifie tout simplement que vous devrez activez un mode spécial de calcul de votre
processeur avant de pouvoir faire tourner ce code. Ce mode (8087) permet une meilleure gestion des
nombres réels. Pour l’activer, Ouvrez le Menu « Options », puis « Compiler ». Dans la boîte de
dialogue qui s’ouvre, vérifiez que la case « Compiler Settings for » est réglée sur « Windows
targets ». Puis cochez l’option « 8087/80287 » de la partie « Numeric Processing ». Puis validez avec
OK. Le code devrait fonctionner sans problèmes désormais.
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
37
4. Calcul Intégral d’une fonction polynomiale
Voilà sans doute l’un des exercices les plus complexes que je propose dans ce document,
mais qui reste de loin le plus intéressant à étudier, et qui vous fera comprendre beaucoup de choses.
L’objectif est simple : concevoir un programme qui calcule l’intégrale d’une fonction entre
deux bornes réelles a et b que l’utilisateur fixe lui-même. Prendre l’exemple de la fonction f(x)=x².
Résolution
Nous allons dans un premier temps mettre au point un algorithme de calcul, que nous allons
ensuite implémenter (traduire) en Pascal.
La technique que nous allons employer est déjà connue : la méthode des trapèzes. Intégrer
une fonction f entre deux points a et b n’est rien d’autre que calculer l’aire sous la courbe de f entre
ces deux points. Et cette aire peut être approchée par une somme de trapèzes de même hauteur p,
cette valeur p étant un pas de découpage de l’intervalle *a,b+.
La somme des surfaces des trapèzes de hauteur p et de bases f(a+ip),f(a+(i+1)p) permet
d’obtenir une approximation de l’intégrale de f sur *a,b+.
Il faut par ailleurs noter que le résultat trouvé est encore meilleur lorsque le pas est de plus
en plus faible. Nous allons donc exploiter ce critère de convergence pour approcher la solution du
problème.
Nous demandons à l’utilisateur de fournir en entrée les bornes a et b sur laquelle il désire
calculer l’intégrale d’une fonction f prédéfinie. Ensuite, l’utilisateur précise le pas de calcul avec
lequel il désire commencer. Par exemple, pour a=2, b = 10 et un pas p = 1, l’intervalle *a,b+ sera divisé
en (b-a)/p soit 8 trapèzes de hauteur p=1. Si nous calculons l’intégrale en sommant l’aire de ces 8
trapèzes, nous obtenons une certaine valeur approchée de ∫ ( ) ( )
. En prenant un pas plus
faible, donc un plus grand nombre de trapèzes, on obtient une valeur encore plus précise. On peut
continuer à diminuer le pas jusqu’à ce que la valeur trouvée à la k-ième itération soit très proche de
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
38
celle trouvée à l’itération précédente…Ce qui implique que l’utilisateur devra préciser à quel niveau
de précision il souhaite arrêter son calcul.
Nous pouvons désormais passer à une implémentation progressive de l’algorithme :
program calcintegral; uses wincrt; {Fonction retournant la surface d'un trapèze de bases b1, b2, et de hauteur h} function tarea(b1,b2,h:real):real; begin tarea:=(b1+b2)*(h/2); end; {fonction retournant le carré de x : représente la fonction à intégrer} function carre(x:real):real; begin carre:=sqr(x); end; {variables globales au programme} var a,b,p0,epsilon,temp,IP,IA:real; i:integer; n_data:longint; begin writeln('Programme de Calcul Intégral de f(x) = x^2'); writeln('Entrez la borne inférieure puis la borne supérieure d''intégration'); {on demande à l'utilisateur les bornes a et b d'intégration. Au cas où il entre une valeur de a plus grande que b, on permute ces valeurs} readln(a,b); if a > b then begin temp:=a; a:=b; b:=temp; end; {on demande à l'utilisateur le pas d'intégration. Au cas où le pas qu'il entre est plus grand que |a-b|, on ramène le pas à |a-b|.} writeln('Entrez le pas d''intégration'); read(p0); if p0 > (b-a) then begin p0:=(b-a); writeln('Pas supérieur à l''intervalle d''intégration. Pas redéfini à ',p0); end; {on demande à l'utilisateur la précision de calcul souhaitée. Cela constituera le critère d'arrêt des itérations}
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
39
writeln('Entrez la précision sur le calcul souhaitée'); read(epsilon); {on double le pas entré par l'utilisateur pour se forcer à commencer par ce pas, on fixe IA à 0} p0:=p0*2; IA:=0; {le calcul intégral commence ici, à la condition que la borne a soit différente de la borne b. Sinon, on renvoie 0.} if a <> b then repeat IP:=IA; p0:=p0/2; writeln('Le pas de calcul courant vaut ',p0); n_data:=trunc(((b-a)/p0))+1; if (a+(n_data*p0))> b then n_data:=n_data-1; IA:=0; for i:=0 to n_data-1 do IA:=IA+tarea(carre(a+(i*p0)),carre(a+(i+1)*p0),p0); until (abs(IP-IA) < epsilon) else IA:=0; writeln('La valeur de l''integrale est: ',IA:0:4); end.
En appliquant ce programme au calcul de ∫
, on obtient la valeur 291.6669, preuve qu’il
fonctionne !
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
40
5. Table de Gauss
La table de Gauss est utilisée en statistiques pour évaluer les probabilités d’occurrence d’un
phénomène caractérisable par une variable suivant une loi normale. L’objectif de cet exercice est de
concevoir un programme qui, lorsqu’il reçoit une valeur t, renvoie p(X<=t).
Résolution
Cela peut paraître au premier abord extrêmement complexe, mais la façon de procéder est
relativement simple, vu que nous avons déjà traité d’un cas similaire presque sans nous en rendre
compte.
Il suffit de savoir que :
| | ∫
√
Mais avant de continuer, nous allons procéder à une rapide démonstration qui vise à
simplifier cette écriture :
On sait que :
∫
√ .
Cette fonction est appelée intégrale de Gauss. Elle est symétrique, ce qui permet d’arriver à
l’écriture :
∫
√
∫
√
∫
√
∫
√
D’où l’expression finale :
∫
√
∫
√
Nous pouvons donc poser le problème de cette manière :
| | ∫
√
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
41
Ce problème est très simple à résoudre, car nous connaissons déjà l’algorithme de calcul de
l’intégrale d’une fonction (voir Exercice 4). Il suffit juste d’adapter la fonction à calculer ici. Ce qui
nous conduit à l’implémentation suivante :
program calcintegral; uses wincrt; {fonction retournant la surface d'un trapèze de bases b1,b2 et de hauteur h} function tarea(b1,b2,h:real):real; begin tarea:=(b1+b2)*(h/2); end; {fonction représentant la loi normale à intégrer} function loinormale(x:real):real; begin loinormale:=(exp(-(x*x)/2))/sqrt(2*pi); end; {variables globales au programme} var t,p0,epsilon,IP,IA:real; isNeg:boolean; i:integer; n_data:longint; begin writeln('Programme de Calcul Intégral de la loi normale centrée reduite'); writeln('Entrez la valeur t correspondant à la probabilité de l''evènement |X <= t| '); {on demande à l'utilisateur la valeur de t. Au cas ou elle est negative, on la prend en signe opposé, et on lui renverra à la fin la valeur de 1 - P|x<=t| } read(t); if t < 0 then begin t:=-t; isNeg:=true; end else isNeg:=false; {on demande à l'utilisateur le pas de calcul qu'il souhaite employer au départ. Ce pas sera modifié pendant l'execution du programme} writeln('Entrez le pas d''intégration'); read(p0); {on demande à l'utilisateur la précision de calcul. Cela servira de critère d'arrêt des iterations} writeln('Entrez la précision sur le calcul souhaitée'); read(epsilon); p0:=p0*2; IA:=0;
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
42
{le calcul integral commence ici} repeat IP:=IA; p0:=p0/2; writeln('Le pas de calcul courant vaut ',p0); n_data:=trunc((t/p0))+1; if ((0+n_data*p0))> t then n_data:=n_data-1; IA:=0; for i:=0 to n_data-1 do IA:=IA+tarea(loinormale((0+i*p0)),loinormale(0+(i+1)*p0),p0); IA:=IA+0.5; if isNeg then IA:=1-IA; until (abs(IP-IA) < epsilon) ; writeln('La valeur de l''integrale est: ',IA:0:5); end. Ici un exemple de calcul de P|X <= 2.45|. Obtient la valeur 0.9926, et la table de Gauss donne 0.9929…Résultat acceptable donc !
Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal
43
En conclusion…
La compilation d’exercices qui ont été traités tout au long de ce document devrait vous
permettre de vous exercer en Pascal. Vous devrez désormais être capables de résoudre sans aide
particulière la plupart des problèmes traités dans la première partie. Ceux de la seconde partie sont
volontairement plus complexes, mais sont d’excellents cals d’études pour les mordus de calculs, et
sait-on jamais, leur permettront de mieux saisir les concepts itératifs, d’approximations, etc.
Les thèmes abordés ne couvrent pas tout le champ d’investigation de la programmation,
hélas, mais vous confèrent une base solide pour attaquer les autres. Certains aspects assez
élémentaires n’ont pas été abordés, notamment les algorithmes de tri de données, qui sont
incontournables. Mais il ne s’agit que d’une version première du présent document, que je pourrai
éventuellement mettre à jour en intégrant ces nouveaux aspects.
Je reste conscient que les codes sources que j’ai présentés ne sont pas forcément les
meilleurs, et certains peuvent être optimisés. Je reste ouvert à toute critique objective, et également
aux questions de compréhension. N’hésitez surtout pas !
En espérant que vous en ferez bon usage !