Aspects d'algorithmique de base

44
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

Transcript of Aspects d'algorithmique de base

Page 1: 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

Page 2: Aspects d'algorithmique de base

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]

[email protected]

Page 3: Aspects d'algorithmique de base

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

Page 4: Aspects d'algorithmique de base

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.

Page 5: Aspects d'algorithmique de base

Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal

4

I. Calculs et opérations numériques

Page 6: Aspects d'algorithmique de base

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 !

Page 7: Aspects d'algorithmique de base

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.

Page 8: Aspects d'algorithmique de base

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

Page 9: Aspects d'algorithmique de base

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

Page 10: Aspects d'algorithmique de base

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 …

Page 11: Aspects d'algorithmique de base

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

Page 12: Aspects d'algorithmique de base

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.

Page 13: Aspects d'algorithmique de base

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

Page 14: Aspects d'algorithmique de base

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.

Page 15: Aspects d'algorithmique de base

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.

Page 16: Aspects d'algorithmique de base

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

Page 17: Aspects d'algorithmique de base

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

Page 18: Aspects d'algorithmique de base

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 :

Page 19: Aspects d'algorithmique de base

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)

Page 20: Aspects d'algorithmique de base

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;

Page 21: Aspects d'algorithmique de base

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)

Page 22: Aspects d'algorithmique de base

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

Page 23: Aspects d'algorithmique de base

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.

Page 24: Aspects d'algorithmique de base

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

Page 25: Aspects d'algorithmique de base

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

Page 26: Aspects d'algorithmique de base

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 : ( )

Page 27: Aspects d'algorithmique de base

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

Page 28: Aspects d'algorithmique de base

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

Page 29: Aspects d'algorithmique de base

Quelques aspects d’algorithmique de base et implémentation en Turbo Pascal

28

II. Itérations, Convergence, Conversions, Approximations,

simulations de problèmes

Page 30: Aspects d'algorithmique de base

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 !

Page 31: Aspects d'algorithmique de base

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.

Page 32: Aspects d'algorithmique de base

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;

Page 33: Aspects d'algorithmique de base

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 ».

Page 34: Aspects d'algorithmique de base

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

Page 35: Aspects d'algorithmique de base

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.

Page 36: Aspects d'algorithmique de base

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).

Page 37: Aspects d'algorithmique de base

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.

Page 38: Aspects d'algorithmique de base

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

Page 39: Aspects d'algorithmique de base

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}

Page 40: Aspects d'algorithmique de base

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 !

Page 41: Aspects d'algorithmique de base

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 :

| | ∫

Page 42: Aspects d'algorithmique de base

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;

Page 43: Aspects d'algorithmique de base

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 !

Page 44: Aspects d'algorithmique de base

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 !