Vous êtes sur la page 1sur 82

CALCULS NUMERIQUES RESOLUS EN

LANGAGE C
Rappels de Cours, Exercices corrigs, Algorithmes, et leurs Codes C

Auteur : Dr . Hatem MOKHTARI, Matre de Confrences


Universit de Constantine, Facult des Sciences de Lingnieur, Dpartement
dElectronique

Prambule
Dans un monde o les quations ne peuvent avoir de solutions analytiques par le calcul direct,
intervient lanalyse et le calcul numrique qui permettent justement de palier cette lacune et
de proposer une solution approche au problme. Les domaines dapplication sont trs
diversifis et pour chaque problme ses conditions aux limites qui dictent le comportement de
la solution (signal lectrique, pression, temprature, etc .).
Lobjectif de ce polycopi est de donner une base de calcul avec un bref rappel de la thorie
mais en insistant plus sur laspect pratique que le formalisme thorique. Afin de ne pas
surcharger le document de thorie et dinterminables dmonstrations, nous avons prfr la
procdure suivante : poser le problme, rappeler les principes fondamentaux de la mthode
numrique en question, et daborder directement des applications concrtes. Nous navons
nanmoins pas nglig laspect algorithmique qui est la base mme dune programmation
exacte et russie. Cest la raison pour laquelle nous avons propos, avant chaque code en C du
problme en question, lalgorithme qui permet justement dcrire le programme de faon
lisible et comprhensible. Le code C est bien document avec des commentaires sur les lignes
juges essentielles au traitement dinstructions ou de boucles permettant lexcution du
programme. A travers ce document, le lecteur peut se rendre compte du ct applicatif qui est
mis en exergue avec des problmes classiques souvent rencontr en lectronique, en
lectromagntisme, en chimie ou en physique de faon gnrale.
Finalement, ce document a pour vocation et objectif de donner ltudiant ou au chercheur un
code C qui a t test et dont lalgorithme peut tre adapt dautres problmes en effectuant
de simples modifications.

Limagination est plus importante que le savoir .Albert Einstein

Dr. Hatem MOKHTARI | Calculs Numriques rsolus en Langage C


2/82

Table des Matires


Chapitre I : Rsolution dEquations Algbriques Non Linaires

Mthode de la Bissection,
Mthode de Newton,
Mthode du Point Fixe

Chapitre II : Rsolution des systmes dquations de forme matricielle A.x = b

Mthode du Pivot de Gauss


Mthode de Jacobi
Mthode de Gauss-Seidel
Mthode de Newton-Raphson

Chapitre III : Rgression Linaire au sens des Moindres Carrs

Approximation de donnes exprimentales par : y = a.x + b

Chapitre IV : Interpolations Polynomiales

Mthode de Lagrange
Mthode de Newton

Chapitre V : Mthodes dIntgration Numrique

Mthode des Rectangles


Mthode des Trapzes
Mthode de Simpson
Mthode de Quadrature de Gauss-Legendre

Chapitre VI : Rsolution dquations diffrentielles ordinaires

Mthode dEuler
Mthode de Runge-Kutta

Rfrences Bibliographiques

3/82

CHAPITRE I
Rsolution dEquations Algbriques Non Linaires
Mthodes Etudies :
Bissection,
Newton,
Point Fixe

I.1. Introduction

4/82

I .2. La mthode de la bissection


Une fonction change de signe au voisinage de la racine. Une racine se trouve dans lintervalle
[a,b] si f(a) et f(b) ont des signes opposs. Toutefois un changement de signe peut tre d non
pas seulement une racine mais aussi une singularit. Alors la mthode est utilise pour
trouver des solutions initiales.

Algorithme de la Bissection
Initialisation
a(0) = a,
b(0) = b, et
x(0) = [a(0)+b(0)]/2
Boucle
Pour k 0 et tant que = |b(k) a(k)| >
Si f(x(k))f(a(k)) < 0
a(k+1) = a(k), b(k+1) = x(k)
Si f(x(k))f(b(k)) < 0
a(k+1) = x(k), b(k+1) = b(k)
x(k+1) = a(k+1)+b(k+1)

Afficher x(k)
5/82

Fin
Code C de la mthode de la bissection
// Le but est de trouver la solution de lquation Ln(x) = 0 (i.e. vrifier que x = 1.0 comme
solution)
// lintervalle est [0,5]
Nom de fichier : BISSECTION.CPP
#include <stdio.h>
#include <stdlib.h>
#include<math.h>
#define A
#define B
#define
#define

0.0 // Borne Infrieure


5.0 // Borne Suprieure
N
100 // Nombre d'itrations
EPS 1.0e-15 // Prcision demande

double f(double x)
{
return log(x); // fonction tester Ln(x) = 0 dans [0, 5]
}
void main()
{
double *a, *b, *x;
a = (double *)calloc(N,sizeof(double));
b = (double *)calloc(N,sizeof(double));
x = (double *)calloc(N,sizeof(double));
a[0] = A; // Initialisation du pointeur *a
b[0] = B; // Initialisation du pointeur *b
x[0] = (a[0]+b[0])/2.0; // Initialisation du pointeur *x
int k=0;
while( k>=0 &&fabs(b[k] - a[k]) > EPS ) // Arrt si un des deux critres est faux
{
if( f(x[k])*f(a[k]) < 0 )
{
a[k+1] = a[k];
b[k+1] = x[k];
}
if( f(x[k])*f(b[k]) < 0 )
{
a[k+1] = x[k];
b[k+1] = b[k];
}
6/82

x[k+1] = (a[k+1]+b[k+1])/2.0;
printf("K = %d \t X = %18.16g\n", k, x[k]);
// Impression du nombre d'itrations, et la solution Ln(x) = 0
k++;
}
delete [] a; // Libration de la mmoire
delete [] b; // Libration de la mmoire
delete [] x; // Libration de la mmoire
}
Le rsultat est rsum par la fentre ci-dessous. La mthode converge aprs 57 itrations
donnant 1 comme solution Ln(x) = 0

I.3. La mthode de Newton


7/82

On utilise cette mthode lorsque lon peut calculer les drives de f(x) de faon analytique. Le
principe de cette mthode consiste tracer la tangente en xi et de chercher lintersection xi+1
avec laxe horizontal et ainsi de suite.

Algorithme de la Mthode de Newton


Donnes : N, x, , f(xi) et f(xi)
Boucle
Pour i=1,N
On calculera :
( )
=
( )
Si |

|<

alors

est une racine

Sinon on continue les itrations (cad i = i+1)

Code C de la mthode de Newton

8/82

// Dans lexemple ci-dessous nous cherchons la racine de lquation Ln(x) = 0 dans


lintervalle ]0, +[ avec x0 comme valeur initiale choisie par lutilisateur
Nom de fichier : Newton.cpp
#include <stdio.h>
#include <stdlib.h>
#include<math.h>
#define EPS 1.0e-15 // Prcision voulue
#define N
1000 // Nombre maximal d'itrations

double f(double x)
{
return log(x); //Ln(x) comme test
}

double df(double x)
{
return 1.0/x; // Drive de Ln(x)
}
voidmain()
{
double x0; // Valeur Initiale
double *x; // tableau des valeurs Xi
x = (double *)calloc(N,sizeof(double));
printf("entrer la valeur initiale X0: \n");
scanf("%lf",&x0);//L'utilisateur choisi une valeur de dpart
x[0] = x0;
for(int i=0;i<N;i++)
{
x[i+1] = x[i] - f(x[i])/df(x[i]); // Calcul des X[i+1] selon Newton
if( fabs(x[i+1] - x[i]) <=EPS) // On test l'ingalit
{
printf("NBRE D'ITERATIONS = %d\t X=%18.16g\n",i,x[i+1]);
exit(0);
}
}
delete [] x;// On libre la mmoire la fin des calculs
}

9/82

Remarque : La commande exit (0) ; permet de sortir du programme et darrter dimprimer


les valeurs dei et x[i+1]
Le rsultat est rsum par la fentre ci-dessous. La mthode converge aprs 6 itrations
donnant 1 comme solution Ln(x) = 0

Application de la mthode de Newton : Circuit RL avec diode de redressement


Le circuit ci-dessous prsente un redresseur simple alternance sur une charge inductive RL.

La rsolution de lquation diffrentielle : ( ) =


lorsque la tension ( ) =

(1)

) on dmontre [1] que le courant dans la charge R L :

(2)
Avec
(3)
(4)
(5)
Pour que le courant i(t) sannule, il faut trouver la solution de lquation
(6)
10/82

Il est clair quil ny a pas de solution analytique lquation (6). Nous nous proposons donc
dutiliser la mthode de Newton vu quil existe une drive de la fonction
( )=

)+

(7)

La drive de f(t) est :


( )=

(8)

/*Le programme en C de la rsolution de lquation (6) et utilisant la Mthode de Newton est


donn ci-dessous. Pour le calcul nous avons pris les valeurs numriques suivantes :
L = 0.01 H
R=5
f = 50 Hz ou T = 0.02 sec ( = 314.159 rd/s)
= L/R = 0.002 sec
La prcision EPS = 10-15
*/
Nom de fichier : Newton_CircuitRL.cpp
#include <stdio.h>
#include <stdlib.h>
#include<math.h>
#define EPS 1.0e-15 // Prcision voulue
#define N
1000 // Nombre maximal d'itrations
#define Omega
314.159
#define
L
1.0e-2
#define
R
5.0
#define Tau
2.0e-3
#define
phi
atan(L*Omega/R)
#define
T
0.02
double f(double t) // la fonction f(t) = 0 dont il faut chercher les racines
{
return sin(Omega*t - phi) + sin(phi)*exp(-t/Tau); // fonction test
}
double df(double t) // la driv de f(t)
{
return Omega*cos(Omega*t - phi) - (sin(phi)*exp(-t/Tau))/Tau;
}
voidmain()
{
double *x; // tableau des valeurs Xi
x = (double *)calloc(N,sizeof(double));
11/82

x[0] = T/2; // on initialise t T/2 vu que le courant s'annule aprs cette valeur
for(int i=0;i<N;i++)
{
x[i+1] = x[i] - f(x[i])/df(x[i]); // Calcul des X[i+1] selon Newton
if( fabs(x[i+1] - x[i]) <=EPS) // On test l'ingalit
{
printf("NBRE D'ITERATIONS = %d\t X=%18.16g\n",i,x[i+1]); //
Affichage de la solution
exit(0);
}
}
delete [] x;// On libre la mmoire la fin des calculs
}

Commentaire sur le rsultat : Lexcution de ce programme nous dmontre bien que le


courant sannule aprs T/2 et avant T, avec T=0.02 seconde. La valeur trouve est 0.01179
seconde, ce qui est conforme aux attentes thoriques.
I.4. La mthode du point fixe
Il sagit la rsolution dune quation de la forme f(x) = 0. On peut aussi lcrire sous la forme
x = (x).Approcher les zros de f() revient dterminer les points fixes de ().
Algorithme de la Mthode du Point Fixe
Donnes : (x), (Prcision voulue), x(0)
Etape 1 : Calcul de x(k+1) = (x(k)) pour k 0
Etape 2 : Si |x(k+1) x(k)| <
Ecrire la solution est x(k+1) et Sortir du programme
Sinon
k= k+1 et reprendre ltape 1

Code C de la mthode du Point fixe


// Dans lexemple ci-dessous Nous cherchons une solution lquation x = e-x avec une
prcision de 10-15
Nom de fichier :PointFixe.cpp
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define

1000
12/82

#define

EPS 1.0e-15 // Prcision voulue

double g(double x)
{
return exp(-x); // fonction test
}
voidmain()
{
double x0,*x;
x = (double *)calloc(N,sizeof(double)); // allocation dynamique

printf("Entrez une valeur initiale X0:");


scanf("%lf",&x0);
x[0] = x0; // Initialisation de la valeur de dpart
int k=0;
do
{
x[k+1] = g(x[k]); // calcul des termes de la srie x(k+1)
if(fabs(x[k+1] - x[k]) <= EPS ) // critre de convergence
{
printf("\n\nNombre d'Iterations K = %d \t La solution X =
%18.16g\n", k, x[k+1]);
exit(0);
}
k++;
}
while(fabs(x[k+1] - x[k]) > EPS );// continuer les calcul tant que le critre n'est
pas atteind
delete [] x;
}

Le rsultat est rsum par la fentre ci-dessous avec x0 = 0.5 comme valeur initiale

13/82

CHAPITRE II
Rsolution des systmes dquations de forme Matricielle A.x = b
Mthodes tudies :
Pivot de Gauss,
Jacobi,
Gauss-Seidel,
Newton-Raphson

14/82

II.1. Introduction
II.2. Mthode du Pivot Gauss
Il sagit de trouver les racines de lquation matricielle A .x = b avec x comme vecteur
inconnue, A une matrice et b vecteur donn (connu).
Cette mthode est la plus simple et la plus classique, elle correspond exactement ce que lon
fait " la main" :
de la premire quation, on exprime la premire inconnue x1en fonction des autres
inconnues, puis on substitue cette expression dans les autres quations du systme, faisant
apparatre ainsi un sous-systme dans lequel x1nintervient pas,
on itre le mme schma jusqu ce que la matrice du systme devienne triangulaire
suprieure (toute la partie infrieure de la matrice sous la diagonale est remplie de zros),
une fois la triangularisation termine, on calcule xn, puis xn-1, et ainsi de suite jusqu x1 ;les
diffrentes solutions sont ainsi calcules de proche en proche.
Le principe de triangularisation permet ainsi de transformer le systme initial

par un systme triangulaire quivalent de la forme

Pour liminer x1de la premire quation, on divise par le coefficient a11de la matrice ; ce
coefficient sappelle le pivot. Il est clairement indispensable que ce coefficient ne soit pas nul.
Nanmoins, ce critre, parfaitement acceptable mathmatiquement, nest pas suffisant
numriquement. En effet, ce coefficient peut tre trs faible, entranant ainsi lapparition de
trs grandes valeurs, et donc de grands risques dimprcisions et derreurs numriques.
En fait, la mthode du pivot de Gauss est rigoureuse mathmatiquement, mais elle conduit
gnralement de nombreux calculs ; la mthode est donc assez sensible aux erreurs
numriques, en particulier pour les systmes de grande taille.

15/82

Une implmentation de cette mthode doit donc imprativement mettre en oeuvre une
stratgie de choix du pivot, consistant recherche le plus grand pivot en valeur absolue ou en
module si lon utilise une matrice valeurs complexes. On a pour cela plusieurs possibilits :
la premire mthode, la plus simple, consiste observer que lon peut indiffremment
inverser lordre des quations, sans changer le systme ni sa solution ; on recherche donc le
| | pour 1 et on permute les quations si ncessaire : la
pivot dfini par
recherche du plus grand pivot se fait donc par colonne,
la deuxime mthode consiste rechercher le plus grand pivot par ligne plutt que par
| | pour 1
colonne ; on recherche donc le pivot dfini par
linconvnient majeur de cette mthode est quelle ne conserve pas le systme initial, mais
quil faut obligatoirement tenir compte dun ragencement des solutions ; cette mthode est
donc plus complique que la prcdente puisque le programme doit mmoriser toute la
squence de ragencements successifs afin de pouvoir remettre les solutions dans le bon
ordre,
la troisime mthode consiste mixer les deux mthodes prcdentes, et donc chercherle
pivot dfini par max (| |, | | ) pour 1 ; la recherche se fait donc sur lignes et
colonnes : cettemthode a gnralement les mmes inconvnients que la prcdente.

Le code C ci-dessous illustre une implmentation de cette mthode de rsolution ; il est


constitu des blocs suivants :
les quatre premires fonctions alloc_vecteur, free_vecteur, alloc_matrice
etfree_matricesont des fonctions gnrales permettant de grer dynamiquement le
stockage des matrices et vecteurs ; ces fonctions sont utilises ici, mais ne font pas partie de
lalgorithme du pivot de Gauss,
les fonctions trouve_pivot, permute_lignesetgauss correspondent la
rsolution par le pivot de Gauss,
la fonction controlenest l que pour vrifier que la solution trouve satisfait bien le
systme initial,
enfin, les fonctions randometmain permettent de tester avec un exemple particulier.
Nom de fichier : PivotGauss.cpp
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define EPS 1.0e-12
//-------------------------------------------------------------// Fonction dallocation dun vecteur (n)
//-------------------------------------------------------------double * alloc_vecteur (int n)
{
return (double *)malloc(n*sizeof(double));
}
16/82

//-------------------------------------------------------------// Fonction de dsallocation d'un vecteur (n)


//-------------------------------------------------------------void free_vecteur (double *v)
{
if (v!=NULL) free((void *)v);
}
//-------------------------------------------------------------// Fonction d'allocation d'une matrice (n,n)
// Remarque : on dsalloue en cas dchec en cours !
//-------------------------------------------------------------double ** alloc_matrice (int n)
{
double **a;
a=(double **)malloc(n*sizeof(double *));
if (a!=NULL)
{
for (int i=0; i<n; i++)
{
a[i]=(double *)malloc(n*sizeof(double));
if (a[i]==NULL)
{
for (int j=0; j<i; j++)
free((void *)a[j]);
free((void *)a);
return NULL;
}
}
}
return a;
}
/*-------------------------------------------------------------Fonction de dsallocation d'une matrice (n,n)
--------------------------------------------------------------*/
void free_matrice (double **a, int n)
{
if (a!=NULL)
{
for (int i=0; i<n; i++)
if (a[i]!=NULL)
free((void *)a[i]);
free((void *)a);
}
}
//-------------------------------------------------------------17/82

// Fonction de recherche du pivot maximum sur une colonne


// et partir d'une ligne spcifie
//-------------------------------------------------------------int trouve_pivot (double **A, int n, int ligne, int colonne)
{
double v,max;
inti,pivot;
for (i=ligne, max=0.0; i<n; i++)
{
v=fabs(A[i][colonne]);
if (v>max)
{
pivot=i; // pivot identifie la ligne contenant le pivot max.
max=v;
}
}
if (max<EPS) pivot=-1; // pivot trop petit !
return pivot;
}
//-------------------------------------------------------------// Fonction de permutation de 2 lignes de la matrice
//-------------------------------------------------------------void permute_lignes (double **A, double *b, intn,int ligne1, int ligne2)
{
double x;
for (int colonne=0; colonne<n; colonne++)
{
x=A[ligne1][colonne];
A[ligne1][colonne]=A[ligne2][colonne];
A[ligne2][colonne]=x;
}
x=b[ligne1];
b[ligne1]=b[ligne2];
b[ligne2]=x;
}
//-------------------------------------------------------------// Cette fonction cherche la solution du systme ax=b
// a est la matrice (n,n), b le second membre (n) et x la solution
// trouve (n), n est la dimension du systme.
// La mthode de Gauss modifie a et b. Pour viter ce problme, on
// duplique a dans A, b dans B, et on utilise A et B pour la mthode
// du pivot de Gauss. On ne modifie donc ni a ni b.
// Valeur retourne : 0 en cas d'erreur
// 1 en cas de succs
//-------------------------------------------------------------18/82

int gauss (double **a, double *b, double *x, int n)


{
interr,pivot,indpivot,ligne,colonne;
double **A,*B,coef;
A=alloc_matrice(n);
if (A==NULL) return 0; // allocation matrice A
B=alloc_vecteur(n); // allocation vecteur B
if (B==NULL)
{
free_matrice(A,n);
return 0;
}
for (ligne=0; ligne<n; ligne++) // copie de a dans A
{
for (colonne=0; colonne<n; colonne++) // et de b dans B
A[ligne][colonne]=a[ligne][colonne];
B[ligne]=b[ligne];
}
err=1; // code derreur
for (pivot=0; pivot<n-1; pivot++)
{
indpivot=trouve_pivot(A,n,pivot,pivot); // recherche du pivot max.
if (indpivot==-1)
{ // problme : pas de pivot satisfaisant
err=0;
break;
}
if (pivot!=indpivot) // permutation lignes si ncessaire
permute_lignes(A,B,n,pivot,indpivot);
for (ligne=1+pivot; ligne<n; ligne++) // calcul de la nouvelle matrice
{
coef=A[ligne][pivot]/A[pivot][pivot];
A[ligne][pivot]=0.0;
for (colonne=1+pivot; colonne<n; colonne++)
A[ligne][colonne]-=A[pivot][colonne]*coef;
B[ligne]-=B[pivot]*coef; // et du nouveau second membre
}
if (fabs(A[pivot][pivot])<EPS) // pivot trop petit : problme dans
{
err=0; // la rsolution finale du systme
19/82

break;
}
}
if (err==1) // si on na pas rencontr derreur
{
for (ligne=n-1; ligne>=0; ligne--) // calcul des solutions, en remontant
de la
{

// dernire jusqu la premire


coef=B[ligne];
for (colonne=1+ligne; colonne<n; colonne++)
coef-=A[ligne][colonne]*x[colonne];
x[ligne]=coef/A[ligne][ligne];

}
}
free_matrice(A,n); // dsallocation de A
free_vecteur(B); // dsallocation de B
return err;
}
//-------------------------------------------------------------// Cette fonction calcule (et affiche) la diffrence Ax-b (contrle)
//-------------------------------------------------------------void controle (double **a, double *b, double *x, int n)
{
double d;
printf("Vecteur Ax-b :\n");
for (int i=0; i<n; i++)
{
d=-b[i];
for (int j=0; j<n; j++) d+=a[i][j]*x[j];
printf("%9.2le \n ",d);
}
}
//-------------------------------------------------------------// Cette fonction renvoie un nombre alatoire entre -range et +range
//-------------------------------------------------------------double random (double range)
{
return range*(1.0-2.0*(double)rand()/RAND_MAX);
}
//-------------------------------------------------------------// Exemple dappel de la fonction gauss
20/82

// 1. on alloue dynamiquement a et b (x=b+n)


// 2. la matrice a est alatoire entre -1 et +1, idem pour b
// 3. on affiche a et b
// 4. on calcule la solution x par la fonction gauss
// 5. on affiche x, puis la diffrence (ax-b)
// 6. on dsalloue a et b
main ()
{
double **a,*b,*x;
int n=5;
a=alloc_matrice(n); if (a==NULL) return 0;
b=alloc_vecteur(2*n);
if (b==NULL)
{
free_matrice(a,n);
return 0;
}
x=b+n;
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j++)
a[i][j]=random(1.0); // Gnrtion alatoire de la matrice a
b[i]=random(1.0); // Gnrtion alatoire du vecteur b
}
printf("\n Matrice a (GENEREE DE FACON ALEATOIRE):\n");
for (int k=0; k<n; k++)
{
for (int j=0; j<n; j++)
printf("%9.6lf ",a[k][j]);
printf("\n");
}
printf("\n Vecteur b (GENERE DE FACON ALEATOIRE):\n");
for (int m=0; m<n; m++)
printf("%9.6lf ",b[m]);
printf("\n\n");
interr=gauss(a,b,x,n);
printf("Retour de la fonction gauss : %d\n",err);
21/82

printf("Solution x :\n");
for (int p=0; p<n; p++)
printf("%9.6lf \n",x[p]);
controle(a,b,x,n); // Permet de vrifier que A.x - b =0
free_matrice(a,n);
free_vecteur(b);
return 0;
}
Lexcution de ce programme donne le rsultat suivant

II.3. Mthode itrative de Jacobi


Lalgorithme de Jacobi scrit, pour x(0) donn, de la forme :
(

( )

Cet algorithme ncessite le stockage de deux vecteurs : x(n) et x(n+1)

II.4. Mthode itrative de Gauss-Seidel


La mthode itrative de Gauss-Seidel est similaire la prcdente, elle scrit de la forme
suivante :

22/82

Le code C ci-dessous regroupe les mthodes itratives cites plus haut, et en rajoute
dautres (cf. littrature en Rfrences)
/*
Rsolution de A x = b par :
Cramer , Inversion , Gauss , Gauss pivot partiel ,
Gauss pivot total , Jordan , Dcomposition LU croot ,
LU doolittle , Cholseky , et les methodes itratives de Jacobie et Gauss-Seidel.
*/
#include "stdafx.h"
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
// ------------------------------------------------------------// Fonctions utiles pour la rsolution par Cramer et inversion
// ------------------------------------------------------------// fonction d'affichage matrice
void aff_mat(double a[19][19],int n)
{
int i,j;
printf("\n\n");
for (i=0;i<n;i++)
{
printf(" [");
for (j=0;j<n;j++)
{
printf(" %.4f ",a[i][j]);
}
printf("]\n");
}
}
// Calcul norme vecteur
double norme(double x[19],int n)
{
double ref;int i;
ref=0;
for(i=0;i<n;i++) if (x[i]>ref) ref=x[i];
return(ref);
}

23/82

// calcul des comatrices


void comatrices(float a[19][19],float c[19][19],int i,int j,int n)
{
int l,k;
for(l=0;l<n;l++) for(k=0;k<n;k++)
{
if ((l<i)&&(k<j)) c[l][k]=a[l][k];
if ((l>i)&&(k<j)) c[l-1][k]=a[l][k];
if ((l<i)&&(k>j)) c[l][k-1]=a[l][k];
if ((l>i)&&(k>j)) c[l-1][k-1]=a[l][k];
}
}
// fonction de remplissage
void remplissage(double a[19][19],double b[19],int n)
{
int i,j;
printf("\n * La matrice A:\n\n");
for (i=0;i<n;i++)
{
printf(" | ");
for (j=0;j<n;j++) scanf_s("%f",&a[i][j]);
}
printf("\n * Le vecteur B:\n\n");
for(i=0;i<n;i++)
{
printf(" | ");
scanf_s("%f",&b[i]);
}
}
// fonction d'affichage systme
void aff_syst(double a[19][19],double b[19],int n)
{
int i,j;
printf("\n\n");
for (i=0;i<n;i++)
{
printf(" [");
for (j=0;j<n;j++)
{
printf(" %.4f ",a[i][j]);
}
printf("] [ %.4f ]",b[i]);
printf("\n");
}
}
24/82

// Mettre Zero les elements qui doivent etre des zro


void zero(double a[19][19],double b[19],int n)
{
int i,j;double eps=1e-4;
for(i=0;i<n;i++)
{
for (j=0;j<n;j++)
if (fabs(a[i][j])<eps) a[i][j]=0;
if (fabs(b[i])<eps) b[i]=0;
}
}
void remplir(double a[19][19], double b[19], int n)
{
printf("\n\n * Nombre d'equation-inconues : \n\n * N = ");
scanf_s("%d",&n);
remplissage(a,b,n);
printf("\n\n * Le systeme est : ");
aff_syst(a,b,n);
}
// Calcul des comatrices
void comatrices(double a[19][19],double c[19][19],int i,int j,int n)
{
int l,k;
for(l=0;l<n;l++) for(k=0;k<n;k++)
{
if ((l<i)&&(k<j)) c[l][k]=a[l][k];
if ((l>i)&&(k<j)) c[l-1][k]=a[l][k];
if ((l<i)&&(k>j)) c[l][k-1]=a[l][k];
if ((l>i)&&(k>j)) c[l-1][k-1]=a[l][k];
}
}
// calcul du determinant
double det(double a[19][19],int n)
{
int k,j;
double c[19][19],s;
k=n-1;
if(n==0) return(1);
s=0;
for(j=0;j<n;j++)
{
25/82

comatrices(a,c,k,j,n);
= s + powl(-1,k+j)*a[k][j]*det(c,k);

s
}
return(s);
}

// ------------------------------------------------------------// Rsolution Par Cramer


// ------------------------------------------------------------void cramer(double a[19][19],double b[19],int n)
{
double A[19][19],x[19],deter;int i,j,k;
deter=det(a,n);
if (deter==0)
{
printf("\n => Determinant nul, pas de solutions \n\n");
system("PAUSE");
//main();
}
for(j=0;j<n;j++)
{
for(k=0;k<n;k++)
{
if (k==j) for(i=0;i<n;i++) A[i][k]=b[i];
else for(i=0;i<n;i++) A[i][k]=a[i][k];
}
x[j]=det(A,n)/deter;
}
printf("\n-------------- Cramer -------------\n");
printf("\n * Le determiant du systeme : %f \n",deter);
printf("\n * La resolution donne :\n\n");
for (i=0;i<n;i++) printf(" X_%d = %f ;\n",i+1,x[i]);
}
// ------------------------------------------------------------// Rsolution Par Inversion
// ------------------------------------------------------------void inversion(double a[19][19],double b[19],int n)
{
double c[19][19],comat[19][19],a_1[19][19],x[19],deter,s;int i,j;
deter=det(a,n);
if (deter==0)
26/82

{
printf("\n => Matrice non inversible, pas de solutions \n\n");
system("PAUSE");
}
for(i=0;i<n;i++) for(j=0;j<n;j++)
{
comatrices(a,c,i,j,n);
comat[i][j]=(powl(-1,i+j)/deter)*(det(c,n-1));
}
// transpose
for(i=0;i<n;i++) for(j=0;j<n;j++)
a_1[i][j]=comat[j][i];
//rsolution
for(i=0;i<n;i++)
{
s=0;
for(j=0;j<n;j++) s=s+a_1[i][j]*b[j];
x[i]=s;
}
printf("\n-------------- Inversion -------------\n");
printf("\n * La matrice inverse A^-1 :");
aff_mat(a_1,n);
printf("\n * La resolution donne :\n\n");
for (i=0;i<n;i++) printf(" X_%d = %f ;\n",i+1,x[i]);
}
// ------------------------------------------------------------// Rsolution Par Gauss
// ------------------------------------------------------------void gauss(double a[19][19],double b[19],int n)
{
double x[19],p,s;int i,j,k;
for(k=0;k<n-1;k++)
{
if (a[k][k]==0)
{
printf("\n\n * Un pivot nul ! => methode de Gauss non applicable\n\n");
system("PAUSE");
}
//rduction
for(i=k+1;i<n;i++)
{
27/82

p=a[i][k]/a[k][k];
for (j=k;j<n;j++) a[i][j]=a[i][j]-p*a[k][j];
b[i]=b[i]-p*b[k];
}
}
//Rsolution
for(i=n-1;i>=0;i--)
{
s=0;
for(j=i+1;j<n;j++)s=s+a[i][j]*x[j];
x[i]=(b[i]-s)/a[i][i];
}
zero(a,b,n);
printf("\n-------------- Gauss -------------\n");
printf("\n * La matrice reduite :");
aff_syst(a,b,n);
printf("\n * La resolution donne :\n\n");
for (i=0;i<n;i++) printf(" X_%d = %f ;\n",i+1,x[i]);
}
// ------------------------------------------------------------// Rsolution Par Gauss pivot pariel
// ------------------------------------------------------------void gauss_pivot_partiel(double a[19][19],double b[19],int n)
{
double x[19],p,s,ref,temp;int i,j,k,ligne;
for(k=0;k<n-1;k++)
{
// max pour le pivot partiel
ref=0;
for(i=k;i<n;i++) if(fabs(a[i][k])>ref) {ref=fabs(a[i][k]);ligne=i;}
// pivotations
for(j=k;j<n;j++)
{temp=a[k][j]; a[k][j]=a[ligne][j] ;a[ligne][j]=temp;}
temp=b[k]; b[k]=b[ligne]; b[ligne]=temp;
if (a[k][k]==0)
{
printf("\n\n* Un pivot nul ! => methode de Gauss pivot partiel non
applicable\n\n");
system("PAUSE");
}

28/82

//rduction
for(i=k+1;i<n;i++)
{
p=a[i][k]/a[k][k];
for (j=k;j<n;j++)
a[i][j]=a[i][j]-p*a[k][j];
b[i]=b[i]-p*b[k];
}
}
//Rsolution
for(i=n-1;i>=0;i--)
{
s=0;
for(j=i+1;j<n;j++) s=s+a[i][j]*x[j];
x[i]=(b[i]-s)/a[i][i];
}
zero(a,b,n);
printf("\n-------- Gauss avec pivot partiel --------\n");
printf("\n * La matrice reduite :");
aff_syst(a,b,n);
printf("\n * La resolution donne :\n\n");
for (i=0;i<n;i++) printf(" X_%d = %f ;\n",i+1,x[i]);
printf("\n");
}
// ------------------------------------------------------------// Rsolution Par Gauss pivot total
// ------------------------------------------------------------void gauss_pivot_total(double a[19][19],double b[19],int n)
{
double x[19],p,s,ref,temp;
int i,j,k,ligne,colonne,pivot_sol[19],temps;
// vecteur de pivotation des solutions
for(i=0;i<n;i++) pivot_sol[i]=i;
for(k=0;k<n-1;k++)
{
// max pour le pivot total
ref=0;
for(i=k;i<n;i++)
for (j=k;j<n;j++)
if(fabs(a[i][j])>ref) {ref=fabs(a[i][j]);ligne=i;colonne=j;}
// pivotations
for(j=k;j<n;j++)
{
29/82

temp=a[k][j];
a[k][j]=a[ligne][j];
a[ligne][j]=temp;
}
temp=b[k];
b[k]=b[ligne];
b[ligne]=temp;
for(i=0;i<n;i++)
{
temp=a[i][k];
a[i][k]=a[i][colonne];
a[i][colonne]=temp;
}

// remplissage du vecteur accord aux pivotations


temps=pivot_sol[k];
pivot_sol[k]=pivot_sol[colonne];
pivot_sol[colonne]=temps;
if (a[k][k]==0)
{
printf("\n\n * Un pivot nul ! => methode de Gauss pivot total non
applicable\n\n");
system("PAUSE");
//main();
}
//rduction
for(i=k+1;i<n;i++)
{
p=a[i][k]/a[k][k];
for (j=k;j<n;j++)
a[i][j]=a[i][j]-p*a[k][j];
b[i]=b[i]-p*b[k];
}
}
// Rsolution
for(i=n-1;i>=0;i--)
{
s=0;
for(j=i+1;j<n;j++)s=s+a[i][j]*b[j];
b[i]=(b[i]-s)/a[i][i];
}
// pivotation des solutions
for(i=0;i<n;i++) x[pivot_sol[i]]=b[i];
30/82

zero(a,b,n);
printf("\n--------- Gauss avec pivot total ---------\n");
printf("\n * La matrice reduite :");
aff_syst(a,b,n);
printf("\n * La resolution donne :\n\n");
for (i=0;i<n;i++) printf(" X_%d = %f ;\n",i+1,x[i]);
printf("\n");
}
// ------------------------------------------------------------// Rsolution Par Jordan
// ------------------------------------------------------------void jordan(double a[19][19],double b[19],int n)
{
double p;int i,j,k;
for(k=0;k<n;k++)
{
if (a[k][k]==0)
{
printf("\n\n * Un pivot nul ! => methode de Jordan non applicable\n\n");
system("PAUSE");
//main();
}
p=a[k][k];
//normalisation
for (j=k;j<n;j++) a[k][j]=a[k][j]/p;
b[k]=b[k]/p;
//rduction
for(i=0;i<n;i++)
{
if (i!=k)
{
p=a[i][k];
for (j=k;j<n;j++) a[i][j]=a[i][j]-p*a[k][j];
b[i]=b[i]-p*b[k];
}
}
}
zero(a,b,n);
printf("\n-------------- Jordan -------------\n");
printf("\n * La matrice reduite :");
aff_syst(a,b,n);
printf("\n * La resolution donne :\n\n");
31/82

for(i=0;i<n;i++) printf(" X_%d = %f ;\n",i+1,b[i]);


printf("\n");
}
// ------------------------------------------------------------// Rsolution Par dcomposition LU Doolittle
// ------------------------------------------------------------void LU_doolittle(double a[19][19],double b[19],int n)
{
double L[19][19],U[19][19],x[19],y[19],s;int i,j,k,m;
for (i=0;i<n;i++) for (j=0;j<n;j++)
{
if(i==j) L[i][j]=1; else L[i][j]=0;
U[i][j]=0;
}
for (m=0;m<n;m++)
{
for (j=m;j<n;j++)
{
s=0;
for (k=0;k<m;k++) s=s+L[m][k]*U[k][j];
U[m][j]=a[m][j]-s;
}
if (U[k][k]==0)
{
printf("\n\n * Un mineur nul ! => methode de LU non applicable\n\n");
system("PAUSE");
//main();
}
for (i=m+1;i<n;i++)
{
s=0;
for (k=0;k<m;k++) s=s+L[i][k]*U[k][m];
L[i][m]=(a[i][m]-s)/U[m][m];
}
}
// resolution
for(i=0;i<n;i++)
{
s=0;
for(j=0;j<i;j++) s=s+L[i][j]*y[j];
y[i]=(b[i]-s)/L[i][i];
}

32/82

for(i=n-1;i>=0;i--)
{
s=0;
for(j=i+1;j<n;j++)s=s+U[i][j]*x[j];
x[i]=(y[i]-s)/U[i][i];
}
printf("\n------------ LU Doolittle -----------\n");
printf("\n * A = L * U \n");
printf("\n * La matrice L :");
aff_mat(L,n);
printf("\n * La matrice U :");
aff_mat(U,n);
printf("\n * La resolution donne :\n\n");
for (i=0;i<n;i++) printf(" X_%d = %f ;\n",i+1,x[i]);
}
// ------------------------------------------------------------// Rsolution Par dcomposition LU Crout
// ------------------------------------------------------------void LU_crout(double a[19][19],double b[19],int n)
{
double L[19][19],U[19][19],x[19],y[19],s;int i,j,k,m;
for (i=0;i<n;i++) for (j=0;j<n;j++)
{
if(i==j) U[i][j]=1; else U[i][j]=0;
L[i][j]=0;
}
for (m=0;m<n;m++)
{
for (i=m;i<n;i++)
{
s=0;
for (k=0;k<m;k++) s=s+L[i][k]*U[k][m];
L[i][m]=a[i][m]-s;
}
if (L[k][k]==0)
{
printf("\n\n* Un mineur nul ! => methode de LU non applicable\n\n");
system("PAUSE");
//main();
}
for (j=m+1;j<n;j++)
{
33/82

s=0;
for (k=0;k<m;k++) s=s+L[m][k]*U[k][j];
U[m][j]=(a[m][j]-s)/L[m][m];
}
}
// resolution
for(i=0;i<n;i++)
{
s=0;
for(j=0;j<i;j++) s=s+L[i][j]*y[j];
y[i]=(b[i]-s)/L[i][i];
}
for(i=n-1;i>=0;i--)
{
s=0;
for(j=i+1;j<n;j++)s=s+U[i][j]*x[j];
x[i]=(y[i]-s)/U[i][i];
}
printf("\n-------------- LU Crout -------------\n");
printf("\n * A = L * U \n");
printf("\n * La matrice L :");
aff_mat(L,n);
printf("\n * La matrice U :");
aff_mat(U,n);
printf("\n * La resolution donne :\n\n");
for (i=0;i<n;i++) printf(" X_%d = %f ;\n",i+1,x[i]);
}
// ------------------------------------------------------------// Rsolution Par dcomposition Cholesky
// ------------------------------------------------------------void cholesky(double a[19][19],double b[19],int n)
{
double L[19][19],Lt[19][19],x[19],y[19],s,p;int i,j,k;
// vrification de le symtrie
for (i=0;i<n;i++) for (j=0;j<n;j++)
if (a[i][j]!=a[j][i])
{
printf("\n\n * Non symetrique => methode de Cholesky non applicable\n\n");
system("PAUSE");
//main();
}
for (i=0;i<n;i++) for (j=0;j<n;j++) L[i][j]=0;

34/82

for (i=0;i<n;i++)
{
s=0;
for (k=0;k<i;k++) s=s+pow(L[i][k],2);
p=a[i][i]-s;
if (p<=0)
{
printf("\n\n * Non definie positive => methode de Cholesky non applicable\n\n");
system("PAUSE");
//main();
}
L[i][i]=sqrt(p);
for(j=i+1;j<n;j++)
{
s=0;
for (k=0;k<i;k++) s=s+L[i][k]*L[j][k];
L[j][i]=(a[j][i]-s)/L[i][i];
}
}
for (i=0;i<n;i++) for (j=0;j<n;j++) Lt[i][j]=L[j][i];
// resolution
for(i=0;i<n;i++)
{
s=0;
for(j=0;j<i;j++) s=s+L[i][j]*y[j];
y[i]=(b[i]-s)/L[i][i];
}
for(i=n-1;i>=0;i--)
{
s=0;
for(j=i+1;j<n;j++) s=s+Lt[i][j]*x[j];
x[i]=(y[i]-s)/Lt[i][i];
}
printf("\n--------------- Cholesky --------------\n");
printf("\n * A = L * Lt \n");
printf("\n * La matrice L :");
aff_mat(L,n);
printf("\n * La matrice Lt :");
aff_mat(Lt,n);
printf("\n * La resolution donne :\n\n");
for (i=0;i<n;i++) printf(" X_%d = %f ;\n",i+1,x[i]);
}

35/82

// ------------------------------------------------------------// Rsolution Par Jacobie


// ------------------------------------------------------------void jacobie(double a[19][19],double b[19],int n)
{
double x[19],x1[19],x2[19],s,eps=1e-4;int i,j,k,iter=0;
//initialisation du vecteur
printf("\n * Veuillez initialisez le vecteur solution : \n\n");
for (i=0;i<n;i++) {printf(" X(0)[%d]= ",i+1);scanf_s("%f",&x1[i]);}
do
{
for(i=0;i<n;i++)
{
s=0;
for (j=0;j<n;j++) if (i!=j) s=s+a[i][j]*x1[j];
x2[i]=(b[i]-s)/a[i][i];
}
for (k=0;k<n;k++) {x[k]=fabs(x1[k]-x2[k]);x1[k]=x2[k];}
iter++;
}
while (norme(x,n)>eps) ;
printf("\n-------------- Jacobie -------------\n");
printf("\n * La resolution donne :\n\n");
for (i=0;i<n;i++) printf(" X_%d = %f ;\n",i+1,x2[i]);
printf("\n * Apres %d iteration, precision 10^-4. \n",iter);
}
// ------------------------------------------------------------// Rsolution Par Gauss-Seidel
// ------------------------------------------------------------void gauss_seidel(double a[19][19],double b[19],int n)
{
double x[19],x1[19],x2[19],s,p,eps=1e-4;int i,j,k,iter=0;
//initialisation du vecteur
printf("\n * Veuillez initialisez le vecteur solution : \n\n");
for (i=0;i<n;i++) {printf(" X(0)[%d]= ",i+1);scanf_s("%f",&x1[i]);}
do
{
for(i=0;i<n;i++)
{
s=0;
p=0;
36/82

for (j=i+1;j<n;j++) s=s+a[i][j]*x1[j];


for (j=0;j<i;j++) p=p+a[i][j]*x2[j];
x2[i]=(b[i]-s-p)/a[i][i];
}
for (k=0;k<n;k++) {x[k]=fabs(x1[k]-x2[k]);x1[k]=x2[k];}
iter++;
}
while (norme(x,n)>eps) ;
printf("\n-------------- Gauss-Saidel -------------\n");
printf("\n * La resolution donne :\n\n");
for (i=0;i<n;i++) printf(" X_%d = %f ;\n",i+1,x2[i]);
printf("\n * Apres %d iteration, precision 10^-4. \n",iter);
}

int _tmain(int argv,_TCHAR *argc[] )


{
double a[19][19],b[19];
int n,i,j;
char valider;
// choix de la methode
printf("\n *******************************************************\n");
printf(" * *\n");
printf(" * Resolution de A x = B *\n");
printf(" * *\n");
printf(" *******************************************************\n");
printf(" * *\n");
printf(" * Choix de la methode : *\n");
printf(" * *\n");
printf(" * A => Cramer *\n");
printf(" * B => Inversion *\n");
printf(" * C => Gauss *\n");
printf(" * D => Gauss pivot partiel *\n");
printf(" * E => Gauss pivot total *\n");
printf(" * F => Jordan *\n");
printf(" * G => LU Doolittle *\n");
printf(" * H => LU Crout *\n");
printf(" * I => Cholesky *\n");
printf(" * J => Jacobie *\n");
printf(" * K => Gauss-Seidel *\n");
printf(" * *\n");
printf(" *******************************************************\n");
printf(" * *\n");
printf(" * X => E X I T *\n");
printf(" * *\n");
printf(" *******************************************************\n\n");
37/82

printf("\n\n * Nombre d'equation-inconues : \n\n * N = ");


scanf_s("%d",&n);
reprendre_choix:
printf("------ => donner votre choix ------ : ");
scanf_s("%s",&valider);

switch(valider)
{
case 'A' : remplir(a,b,n);cramer(a,b,n); break;
case 'B' : remplir(a,b,n);inversion(a,b,n); break;
case 'C' : remplir(a,b,n);gauss(a,b,n); break;
case 'D' : remplir(a,b,n);gauss_pivot_partiel(a,b,n); break;
case 'E' : remplir(a,b,n);gauss_pivot_total(a,b,n); break;
case 'F' : remplir(a,b,n);jordan(a,b,n); break;
case 'G' : remplir(a,b,n);LU_doolittle(a,b,n); break;
case 'H' : remplir(a,b,n);LU_crout(a,b,n); break;
case 'I' : remplir(a,b,n);cholesky(a,b,n); break;
case 'J' : remplir(a,b,n);jacobie(a,b,n); break;
case 'K' : remplir(a,b,n);gauss_seidel(a,b,n); break;
case 'X' : printf("\nProgramme interompu par l'utilisateur.......\n\n");
system("PAUSE");exit(0); break;
default : goto reprendre_choix;
}
printf("\n");
system("PAUSE");
return 0;
}

38/82

CHAPITRE III
Rgression Linaire au sens des moindres carrs
Approximation de donnes exprimentales par :

y = a.x +b

39/82

III .1. Problmatique


Nous nous intressons un problme qui se pose souvent aux exprimentateurs. A l'issue
d'une exprience, un exprimentateur a souvent enregistr des donnes relatives par exemple
l'observation d'un phnomne physique. Ces donnes sont toujours entaches de bruit (le
plus souvent d aux instruments utiliss). L'exprimentateur souhaite nanmoins comparer ses
donnes un modle. Nous ne nous intresserons ici qu'au cas o le modle est connu.
L'exprimentateur souhaite donc uniquement s'assurer que le phnomne observ suit bien la
loi o le modle qu'il connat. Il souhaitera galement dterminer les valeurs numriques des
paramtres intervenant dans ce modle, et qui ne sont pas connues priori.
III.2. Ajustement dune fonction linaire : y = a.x + b
L'exprimentateur est en possession de n donnes (xi, yi) issues de mesures par exemple. La
loi connue s'exprime comme y = f(x, p1, p2, , pm). Cette loi dpend des paramtres p qui ne
sont pas ncessairement connus. Pour vrifier si les donnes se superposent correctement la
loi f, il suffit de calculer les carts yi-f(x,pj) en faisant varier la valeur de pj jusqu' ce que
l'cart soit minimal (o nul si l'accord est parfait). Il faut bien videmment raliser ce calcul
pour tous les points exprimentaux. Les statistiques nous offrent une manire lgante de
calculer cela. On introduit pour cela une variable dpendant des paramtres pj que l'on
appelle 2. Cette variable est dfinie comme

On va ensuite chercher l'ensemble de paramtres pj qui va minimiser 2


Dans ce cas prcis, 2s'exprimera par lquation quadratique :

On cherche minimiser cette grandeur, on va donc chercher satisfaire les conditions

Et

on en dduit que

Et
40/82

On trouve ainsi les deux paramtres a et b qui minimisent le 2, c'est dire les paramtres qui
fournissent le meilleur accord entre les donnes exprimentales (xi, yi) et la fonction y. La
valeur numrique de 2 va nous renseigner sur cet accord. Une valeur nulle indiquera un
accord parfait entre les donnes et le modle, plus la valeur sera grande, moins bon sera
l'accord. C'est ensuite l'utilisateur de cette mthode de dterminer quelles valeurs peuvent
tre satisfaisantes ou pas.
Exemple dapplication
Soit les donnes exprimentales du tableau ci-dessous.
x
0
1
2
3
4
5
6
7

y
1
1,5
2,1
2,6
3,5
4,9
5,3
6,2

On cherche donc les paramtres a et b qui minimisent 2


#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define

double a, b;
// fonction qui calcul a et b selon les quations ci-dessus
voidcalcul_a_b(int n, double *a,double *b, double *x, double *y)
{
double A=0,B=0,C=0,D=0;
double S1 =0.0,S2 = 0.0;
double S3=0.0, S4=0.0;
for(int i=0;i<n;i++)
{
A += x[i]*y[i];
S1 += x[i];
S2 += y[i];
S3 += x[i]*x[i];
}
41/82

A *= n;
B = S1*S2;
C = n*S3;
D = S1*S1;
*a = (A-B)/(C-D);
*b = (S3*S2 - (A/n)*S1)/(C - D);
}
//Fonction qui calcule X2 minimale
double Khi2(int n, double a,double b, double *x,double *y)
{
double valeur;
valeur = 0.0;
for(int k=0;k<n;k++)
{
valeur += (a*x[k] + b - y[k])*(a*x[k] + b - y[k]);
}
return valeur;
}

voidmain()
{
double *x,*y;
x = (double *)calloc(N,sizeof(double));
y = (double *)calloc(N,sizeof(double));
// Initialisation des abscisses
x[0] = 0.0;
x[1] = 1.0;
x[2] = 2.0;
x[3] = 3.0;
x[4] = 4.0;
x[5] = 5.0;
x[6] = 6.0;
x[7] = 7.0;
//Initialisation des ordonnes
y[0] = 1.0;
y[1] = 1.5;
y[2] = 2.1;
y[3] = 2.6;
y[4] = 3.5;
y[5] = 4.9;
y[6] = 5.3;
y[7] = 6.2;
42/82

// calcul de a et b
calcul_a_b(N,&a,&b,x,y);
printf("a = %18.16g \n\n",a);
printf("b = %18.16g \n\n",b);
// callcul de X2
double KHI2 = Khi2(N,a,b,x,y);
printf("KHI2 = %18.16g \n\n",KHI2);
}

Lexcution de ce programme nous donne le rsultat suivant pour notre exemple prcis

43/82

CHAPITRE IV
Interpolations Polynomiales tudies :
Lagrange,
Newton

IV.1. Mthode dinterpolation de Lagrange

44/82

Soit une fonction f (inconnue explicitement)


connue seulement en certains points x0,x1xn
ou valuable par un calcul coteux.
Principe :
reprsenter f par une fonction simple, facile valuer
Problme :
il existe une infinit de solutions !
2
1
0
-1
-2
-3
-4
0

0.2

0.4

0.6

0.8

Il faut se restreindre une famille de fonctions


polynmes,
exponentielles,
fonctions trigonomtriques

Interpolation polynomiale
polynmes de degr au plus n
polynmes de Lagrange
diffrences finies de Newton

1.2

1.4

1.6

1.8

45/82

46/82

47/82

Le code C de linterpolation de Lagrange


// polynomeLagrange.cpp : dfinit le point d'entre pour l'application console.
//
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
double lagrange(double *x,double *y,int n,double val)
{
int i,j;
double prod;
double som;
som=0;
for(i=0;i<=n;i++)
{
prod=1;
for(j=0;j<i;j++)
prod*=(val-x[j])/(x[i]-x[j]);
for(j=i+1;j<=n;j++)
prod*=(val-x[j])/(x[i]-x[j]);
som+=prod*y[i];
}
return som;
}
48/82

int _tmain(int argc, _TCHAR* argv[])


{
double val,res;
double x[50],y[50];
int i,j;
int n;
printf("donner le degre du polynome \n");
scanf_s("%d",&n);
for(j=0;j<=n;j++)
{
printf("element X[%d]= ",j);
scanf_s("%lf",&x[j]);
}
for(j=0;j<=n;j++)
printf("%.2lf\n\n",x[j]);
for(i=0;i<=n;i++)
{
printf("element Y[%d] ",i);
scanf_s("%lf",&y[i]);
}
for(i=0;i<=n;i++)
printf("%.2lf\n\n",y[i]);
printf(" donner la valeur de x: \n");
scanf_s("%lf",&val);
res=lagrange(x,y,n,val);
printf("P(%.2lf)=%.2lf\n",val,res);
system("PAUSE");
return 0;
}
Lexcution du programme donne le rsultat suivant :

49/82

IV.1. Mthode dinterpolation de Newton


Lalgorithme de Newton propose dinterpoler des donnes exprimentales (Xi,Yi) par le
polynme suivant :
( )=

)+

)(

)+ +

)(

)(

Avec
( )=

pour i=0,,n

On dmontre que le polynme Pn(x) scrit sous la forme :


( )=

)+

)(

(
)(

)(

)+

On posera Cn
=

Les ny0 se calculent par la formule gnrale :

( )

Avec

!
! ( )!
50/82

Exemple de calcul :
Nous voulons produire le polynme de Newton pour la fonction reprsente par lchantillon
du tableau suivant :
xi
yi

0
1

1
4

2
8

3
14

Le programme en C ci-dessous illustre notre exemple


/// INTERPOLATION POLYNOMIALE DE NEWTON
#include
#include
#include
#include

"stdafx.h"
<math.h>
<stdlib.h>
<stdio.h>

const double h=1.0; // Pas des abscisses quidistants Xi+1 - Xi


const int n=3; // degr du polynme
// Polynme de Newton pour la variable t
double P(double t, double *x, double *C)
{
double val, Prod;
val = 0.0;
for(int i=1;i<=n;i++)
{
Prod = 1.0;
for(int j=1;j<=i;j++)
{
Prod*= (t-x[j-1]);
}
val += C[i]*Prod;
}
return val + C[0];
}
// fonction factorielle dun entier
double fact(int m)
{
double value=1;
if (m == 0)
{
return 1;
}
else
{
for(int i=0;i<m;i++)
{
value *= (m-i);
}
}
return value;

51/82

}
// Combinaison de p parmi n
double comb(int m, int p)
{
return fact(m)/(fact(p)*fact(m-p));
}
//Calcul des Delta Y0 : somme des K termes
double DeltaY(double *y,int k)
{
double value = 0.0;
int m=0;
do
{
value += comb(k,m)*y[k-m]*pow(-1.0,m);
m++;
}
while(m<=k);
return value;
}
// fonction qui renvoie les poids Ci du Polynme de Newton
void Ccalc(double *C,double *y, int k)
{
if (k == 0)
C[0] = y[0];
else
C[k] = DeltaY(y,k)/(fact(k)*pow(h,k));
}
int _tmain(int argc, _TCHAR* argv[])
{
double value,*x,*C,*y;
x = (double*)calloc(n+1,sizeof(double));
y = (double*)calloc(n+1,sizeof(double));
C = (double*)calloc(n+1,sizeof(double));
// ici on a pris 0, 1,2,3 pour abscisses equidistants
for(int i=0;i<=n;i++)
x[i] = i;
// ici on dfinit nos donnes exprimentales (cad les f(xi) )
y[0] = 1.0;
y[1] = 4.0;
y[2] = 8.0;
y[3] = 14.0;
// cette boucle calcule tous les Ci
for(int i=0;i<=n;i++)
{
Ccalc(C,y,i);
printf("\n C[%d] = %g\n",i,C[i]);
}
// on veut calculer la valeur du polynme de Newton pour x=2.0
value = P(2.0, x, C);
printf("\n\nValue = %18.16g \n\n",value);

52/82

free(x);
free(C);
free(y);
system("pause");
return 0;
}

En excutant ce programme, pour x=2 on trouve le rsultat suivant :

Ce qui correspond bien la valeur pour x=2 (cad y = 8)


Le polynme, aprs tous calculs, se rduit :

( )=

Prenons un autre exemple un peu plus complexe o le nombre de points est important
La fonction tudier est donne par le tableau ci-dessous :
Xi
-10,00
-9,00
-8,00
-7,00
-6,00
-5,00
-4,00
-3,00
-2,00
-1,00
0,00
1,00
2,00
3,00
4,00
5,00
6,00
7,00
8,00
9,00
10,00

Yi
0,37
0,44
0,53
0,61
0,70
0,78
0,85
0,91
0,96
0,99
1,00
0,99
0,96
0,91
0,85
0,78
0,70
0,61
0,53
0,44
0,37
53/82

Constatons quil y a 21 valeurs pour xi et 21 pour yi. Il suffit donc de poser n = 20 et le tour
est jou. Noublions pas que le pas constant h = 1 ici aussi et que les enregistrements de xi et
yi doivent bien tre renseigns dans le code source. Ce dernier scrit alors comme suit :
#include
#include
#include
#include

"stdafx.h"
<math.h>
<stdlib.h>
<stdio.h>

const double h=1.0;


const int n=20; //Polynme de degr 20
double P(double t, double *x, double *C)
{
double val, Prod;
val = 0.0;
for(int i=1;i<=n;i++)
{
Prod = 1.0;
for(int j=1;j<=i;j++)
{
Prod *= (t-x[j-1]);
}
val += C[i]*Prod;
}
return val + C[0];
}
double fact(int m)
{
double value=1;
if (m == 0)
{
return 1;
}
else
{
for(int i=0;i<m;i++)
{
value *= (m-i);
}
}
return value;
}
double comb(int m, int p)
{
return fact(m)/(fact(p)*fact(m-p));
}
double DeltaY(double *y,int k)
{
double value = 0.0;
int m=0;
do

54/82

{
value += comb(k,m)*y[k-m]*pow(-1.0,m);
m++;
}
while(m<=k);
return value;
}
void
{

Ccalc(double *C,double *y, int k)


if (k == 0)
C[0] = y[0];
else
C[k] = DeltaY(y,k)/(fact(k)*pow(h,k));

}
int _tmain(int argc, _TCHAR* argv[])
{
double value,*x,*C,*y;
x = (double*)calloc(n+1,sizeof(double));
y = (double*)calloc(n+1,sizeof(double));
C = (double*)calloc(n+1,sizeof(double));
for(int i=0;i<=n;i++) // On gnre les xi de -10 +10
x[i] = -10 + i;
y[0] = 0.37;
y[1] = 0.44;
y[2] = 0.53;
y[3] = 0.61;
y[4] = 0.70;
y[5] = 0.78;
y[6] = 0.85;
y[7] = 0.91;
y[8] = 0.96;
y[9] = 0.99;
y[10] = 1.00;
y[11] = 0.99;
y[12] = 0.96;
y[13] = 0.91;
y[14] = 0.85;
y[15] = 0.78;
y[16] = 0.70;
y[17] = 0.61;
y[18] = 0.53;
y[19] = 0.44;
y[20] = 0.37;
for(int i=0;i<=n;i++)
{
Ccalc(C,y,i);
printf("\n C[%d] = %g\n",i,C[i]);
}
value = P(2.0, x, C);
printf("\n\nValue = %18.16g \n\n",value);
free(x);

55/82

free(C);
free(y);
system("pause");
return 0;
}

Lexcution du programme nous donne le rsultat suivant :

La valeur de 0.9600000000041672 correspond bien P20(2) qui en fait bien la valeur de 0.96
dans le tableau
Si nous souhaitons calculer une valeur intermdiaire de yi pour xi autre que celle du tableau, il
suffit de remplacer la valeur choisi dans le code : soir la ligne
value = P(2.0, x, C);

Exemple : si x=0.5, alors le rsultat est P20(0.5) = 0.99747872, ce qui est proche de 1,
valeur de y pour x=0.
56/82

CHAPITRE V
Intgration numrique
Mthodes tudies :
Carrs,
Trapzes,
Simpson,
Quadrature de Gauss-Legendre

57/82

V.1. Introduction
Lobjectif de ce chapitre est de calculer numriquement lintgrale dune fonction. Selon les
travaux de Riemann, lintgrale dune fonction peut sinterprter comme laire sous la courbe
reprsentative de cette fonction. Le calcul numrique dune intgrale se rduit donc
lestimation dune aire. Plusieurs mthodes sont possibles selon le type dapproximation
ralise sur la courbe.
V.2. Rappels mathmatiques
Si une fonction f est positive, son intgrale sur un intervalle [a,b] permet dvaluer laire sous
la courbe reprsentative de la fonction.
Lide de Riemann fut de remplacer un arc de courbe correspondant un petit intervalle[xn ,
xn+1] par un segment horizontal dordonne f( (xn + xn+1)/2 ). On parle alors de fonction en
escalier.
La figure suivante illustre le procd de Riemann :

A partir dune subdivision de [a,b] en N intervalles, la somme dfinie par


=

) ( )avec

=(

)/2

est une somme de Riemann attache f sur lintervalle [a, b] .


Lorsque N tend vers linfini, de sorte que les pas cntendent vers 0, la somme SNadmet une
limite finie appele intgrale de f sur [a,b] .
V.3.Mthode des Rectangles
La mthode des rectangles consiste remplacer les arcs de la courbe par des
segments"horizontaux". La mthode converge "lentement" et ncessite donc de grandes
valeurs de N pour obtenir un rsultat acceptable.
58/82

Ce principe permet le calcul approch dintgrales en choisissant une subdivision rgulire


avec des pas constants :

= = ( )/
On obtient alors une succession de rectangles approchant laire sous la courbe.
lim

( )

La mthode de calcul consiste donc calculer :

59/82

Algorithme de la Mthode des Rectangles


Donnes : f(x), a, b
Lutilisateur dfini la prcision souhaite et donc N
On dfinit un Tableau x[ ] de dimension N
Calcul : h = (b-a)/N
Somme = 0.0
Pour i = 1 N
{
x[i] = a + i*h
Somme = Somme + f(x[i] + h/2)
}
SRectangles = h*Somme
Afficher SRectangles
Fin

Exemple ;
On souhaite calculer lintgrale de la fonction suivante :
( )=
Dans lintervalle : [0, 1]
Le code C de la Mthode des Rectangles
#include <stdio.h>
#include <stdlib.h>
#include<math.h>
#define a
#define b
#define

0.0 // Borne infrieure d'intgration


1.0 // Borne suprieure d'intgration
N
100 // Nombre de points

double
f(double x)
{
return exp(-x); // fonction intgrer
}
void main()
{
double *x;
x = (double *)calloc(N, sizeof(double)); // Allocation dynamique des abscisses
xi
double Somme, I;

60/82

double h = (b-a)/N; // Pas d'intgration


Somme = 0.0;
for(int i=1;i<=N;i++) // l'indice s'arrte N
{
x[i] = a +i*h;
Somme += f(x[i] + h/2); // calcul de la somme
}
I = Somme*h; // valeur finale de l'intgrale
printf("\n L'integrale I = %18.16g \n\n",I); // Affichage du rsultat
delete [] x; // Libration de la mmoire
}
Lexcution du programme donne le rsultat suivant

Remarque : Pour ce cas prcis, on peut vrifier ce rsultat en le


comparant avec le calcul analytique.
= [

] =1

= 0,6321205

Lerreur est de 0,0062923 soit 0.995 %

61/82

V.4.Mthode des Trapzes


Le principe de cette mthode est analogue celui de l'intgration par une srie de rectangles.
Dans cette mthode on cherche augmenter la prcision du calcul tout en vitant la
dissymtrie qui apparat dans la dfinition de l'intgration par rectangles. Nous allons donc ici
aussi tabuler en (n+1) points f0,f1,fn dans l'intervalle d'intgration [x0,xn]. On va ensuite
interpoler linairement (polynme d'ordre 1, c.a.d. une droite) pour approximer f(x) entre
deux points tabuls. On va donc remplacer les arcs xi, xi+1 par leurs cordes

L'intgration va alors se faire en sommant l'aire des trapzes, soit

si l'chantillonnage des points est rgulier, c.a.d. si xi+1 xi = h alors l'intgrale s'exprimera

en effet chaque trapze aura chacun de ces cts en commun avec les trapzes adjacents,
l'exception du premier et du dernier qui n'ont qu'un ct en commun.

62/82

Algorithme de la Mthode des Trapzes


Donnes : f(x), a, b
Lutilisateur dfini la prcision souhaite et donc N
On dfinit un Tableau x[ ] de dimension N
Calcul : h = (b-a)/N
Somme = 0.0
Pour i = 1 N-1
{
x[i] = a + i*h
Somme = Somme + f(x[i] + h/2)
}
Finpour
Somme = Somme + 0.5*( f(a) + f(b) )
STrapzes = h*Somme
Afficher STrapzes
Fin
Exemple ;
On souhaite calculer lintgrale de la fonction suivante :
( )=
Dans lintervalle : [0, 1]
Le code C de la Mthode des Trapzes
#include <stdio.h>
#include <stdlib.h>
#include<math.h>
#define a
#define b
#define

0.0 // Borne infrieure d'intgration


1.0 // Borne suprieure d'intgration
N
100 // Nombre de points

double
f(double x)
{
return exp(-x); // fonction intgrer
}
voidmain()
{
double *x;
x = (double *)calloc(N, sizeof(double)); // Allocation dynamique des abscisses
63/82

xi
double Somme, I;
double h = (b-a)/N; // Pas d'intgration
Somme = 0.0;
for(int i=1;i<N;i++) // remarquons que l'indice s'arrte N-1
{
x[i] = a + i*h; // calcul des abscisses xi
Somme += f(x[i]); // calcul de la somme
}
Somme += 0.5*( f(a) + f(b) );
I = Somme*h; // valeur finale de l'intgrale
printf("\n L'integrale I = %18.16g \n\n",I); // Affichage du rsultat
delete [] x; // Libration de la mmoire
}
Lexcution du programme donne le rsultat suivant

Remarque : Pour ce cas prcis, on peut vrifier ce rsultat en le


comparant avec le calcul analytique.
= [

] =1

= 0,6321205

Lerreur est de 0,0000053soit 0.0008 % (nettement meilleur que la


mthode des rectangles)

64/82

V.4.Mthode de Simpson
Comme les autres mthodes, cette mthode est base sur une distribution fi de la
fonction f(x) que l'on interpole. La mthode de Simpson correspond au cas de l'interpolation
parabolique (polynme d'ordre 2 passant par 3 points fi).

L'expression de l'intgrale sur un intervalle de calcul de (2n+1) points s'exprime alors :

f1 correspond f(a)
fn correspond f(b)
fi = f(xi) avec xi = a + i*h
Algorithme de la mthode de Simpson
Donnes : f(x), a, b
Lutilisateur dfini la prcision souhaite et donc N
On dfinit un Tableau x[ ] de dimension N
Calcul : h = (b-a)/N
SommeImpaire = 0.0
Pour i = 1 N-1
{
Si i impaire alors
x[i] = a + i*h
SommeImpaire = SommeImpaire + f(x[i])
Sinon
65/82

i = i+1
}
Finpour
Sommepaire = 0.0
Pour i = 1 N-1
{
Si i paire alors
x[i] = a + i*h
Sommepaire = Sommepaire + f(x[i])
Sinon
i = i+1
}
Finpour
Somme = SommePaire + SommeImpaire
STrapzes = (h/3)*( f(a) + f(b) + Somme)
Afficher STrapzes
Fin
Le code C de la Mthode de Simpson
// METHODE D'INTEGRATION : SIMPSON
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define a
#define b
#define

0.0 // Borne infrieure d'intgration


1.0 // Borne suprieure d'intgration
N
100 // Nombre de points

double
f(double x)
{
return exp(-x); // fonction intgrer
}
void main()
{
double *x;
x = (double *)calloc(N, sizeof(double)); // Allocation dynamique des abscisses
xi
double Somme_Paire, Somme_Impaire, I;
double h = (b-a)/N; // Pas d'intgration
66/82

int i;
Somme_Impaire = 0.0;
for(int j=0; j<= (int)(N/2 - 1); j++) // remarquons que l'indice s'arrte N-1 pour
i impaire
{
i = 2*j + 1; // astuce pour utiliser i impaire
x[i] = a + i*h; // calcul des abscisses xi
Somme_Impaire += f(x[i]); // calcul de la somme des termes indice
impaire
}
i = 0; // Ici on initialise i pour calculer les termes paires
Somme_Paire = 0.0;
for(int k=1; k<= (int)((N-2)/2); k++) // remarquons que l'indice s'arrte N-2
pour i paire
{
i = 2*k; // astuce pour utiliser i paire
x[i] = a + i*h; // calcul des abscisses xi
Somme_Paire += f(x[i]); // calcul de la somme des termes indice
ipaire
}
I = (h/3)*( f(a) + f(b) + 4*Somme_Impaire + 2*Somme_Paire );
// valeur finale de l'intgrale
printf("\n L'integrale I = %18.16g \n\n",I); // Affichage du rsultat
delete [] x; // Libration de la mmoire
}

Lexcution du programme donne le rsultat suivant

Comparaison de la prcision des trois mthodes avec la mthode analytique

Erreur
Absolue
Erreur
Relative

Rectangle

Trapzes

0,62582824

0,63212582

0,00629231
0,9954%

Simpson

0,63212055

Analytique

0,63212055

-5,27E-06 0,0000000000000
-0,0008%

0,0000%

La mthode analytique est prise comme rfrence vu quelle est exacte. En utilisant
exactement les mmes hypothses : Nombres de points, bornes, pas de calcul, fonctions
67/82

intgrer, on voit clairement lamlioration de la prcision de gauche droite dans le tableau


ci-dessus.
V.5. Mthode de Quadrature de Gauss-Legendre
Le domaine d'intgration [a, b] doit tre chang (au moyen d'un changement de variable) en [1, 1] avant d'appliquer les mthodes de quadrature de Gauss. Le changement se droule ainsi :

L'approximation de la valeur de l'intgrale devient :

o xi sont les racines du polynme de Legendre de degr


et o wi sont les poids de ces racines,
Les premiers polynmes sont alors :

...
Une excellente prcision est garantie ds que n>2. Des tables permettent d'obtenir les valeurs
des points et leurs poids.
Exemple pour n = 3, Abscisses et Poids
mro

Abscisse

Poids

68/82

Code C de la mthode de Gauss-Legendre : Intgration =


#include
#include
#include

<stdio.h>
<stdlib.h>
<math.h>

#define EPS 3.0e-11


// Cette fonction calcul les poids w et les Abscisses x
void ploynomes_GaussLegendre(double
x1,double
*w,int n)
{
int m,j,i;
double z1,z,xm,xl,pp,p3,p2,p1;

x2,double

*x,double

m=(n+1)/2;
xm=0.5*(x2+x1);
xl=0.5*(x2-x1);
for (i=1;i<=m;i++) {
z=cos(3.141592654*(i-0.25)/(n+0.5));
do {
p1=1.0;
p2=0.0;
for (j=1;j<=n;j++) {
p3=p2;
p2=p1;
p1=((2.0*j-1.0)*z*p2-(j-1.0)*p3)/j;
}
pp=n*(z*p1-p2)/(z*z-1.0);
z1=z;
z=z1-p1/pp;
} while (fabs(z-z1) > EPS);
x[i]=xm-xl*z;
x[n+1-i]=xm+xl*z;
w[i]=2.0*xl/((1.0-z*z)*pp*pp);
w[n+1-i]=w[i];
}
}
#undef EPS

#define
#define

PI
N

acos(-1.0)
10

//calcul l'intgrale de n'importe quelle fonction entre a et b


69/82

//Utilisant la mthode de Gauss-Legendre


double integrale_gauss(double (*func)(double),double a,double b)
{
int j;
double xr,xm,dx,s;

double *x,*w;
x = (double *)calloc(N,sizeof(double));
w = (double *)calloc(N,sizeof(double));
ploynomes_GaussLegendre(a,b,x,w,N-1); //calcul des poids w et des abscisses x
xm=0.5*(b+a);
xr=0.5*(b-a);
s=0;
for (j=1;j<N;j++) {
dx=xr*x[j];
s += w[j]*((*func)(xm+dx)+(*func)(xm-dx));
}
delete []x;
delete []w;
return s *= xr;
}
// Fonction intgrer
double f(double x)
{
return (1/sqrt(2*PI))*exp(-x*x); // Gaussienne
}
void
{

main()
double I;
double A=0;
double B=1.0;
I = integrale_gauss(f,A,B);
printf("I= %18.16g\n",I);

}
Lexcution de ce programme donne le rsultat suivant :

Prenons encore quelques autres exemples afin de donner au lecteur lopportunit de voir
comment on peut effectivement rutiliser ce code sans trop defforts.
70/82

Problme :
On sait que le champ radiolectrique reu par un mobile GSM en zone urbaine suit une
distribution log-normale lorsque la puissance reue est exprime en Watt. Comme la notion
de dBm est plus largement utilise, cette mme puissance reu suit une distribution
gaussienne (ou normale) quand elle est exprime en dBm. La densit de probabilit est
donne par lquation :
( )=

Avec m la valeur mdiane (assurant 50% de probabilit) et lcart type


Loprateur Mobilis, par exemple, souhaite savoir avec quelle probabilit de couverture un
utilisateur de son rseau peut tre desservie avec un niveau de puissance radiolectrique
suprieure x0 = -50 dBm et infrieur x1 = 0 dBm, sachant que la mdiane de cette
puissance est de m= -75 dBm. Lcart type est de = 7 dB.
Solution :
On calcule la probabilit par la formule :
( >

)=

( )

Le programme en C (hrit du code C ci-dessus) et simplement crit en changeant la fonction


f(x) et les bornes dintgration. Les valeurs de m et sont des constantes que lon peut
dclarer avant le main() comme tant des constantes globales. Et le tour est jou !

// gausslegendre_GSM.cpp : dfinit le point d'entre pour l'application console.


//
#include
"stdafx.h"
#include
<stdio.h>
#include
<stdlib.h>
#include
<math.h>
#define EPS 3.0e-11
#define
#define
#define
#define

S
M1
PI
N

7 // 7 dB cart type
-75.0 // -75 dBm de valeur mdiane
3.141592654
100

// Cette fonction calcul les poids w et les Abscisses x


void ploynomes_GaussLegendre(double
x1,double
*w,int n)
{
int m,j,i;
double z1,z,xm,xl,pp,p3,p2,p1;

x2,double

*x,double

71/82

m=(n+1)/2;
xm=0.5*(x2+x1);
xl=0.5*(x2-x1);
for (i=1;i<=m;i++) {
z=cos(3.141592654*(i-0.25)/(n+0.5));
do {
p1=1.0;
p2=0.0;
for (j=1;j<=n;j++) {
p3=p2;
p2=p1;
p1=((2.0*j-1.0)*z*p2-(j-1.0)*p3)/j;
}
pp=n*(z*p1-p2)/(z*z-1.0);
z1=z;
z=z1-p1/pp;
} while (fabs(z-z1) > EPS);
x[i]=xm-xl*z;
x[n+1-i]=xm+xl*z;
w[i]=2.0*xl/((1.0-z*z)*pp*pp);
w[n+1-i]=w[i];
}
}
#undef EPS

//calcul l'intgrale de n'importe quelle fonction entre a et b


//Utilisant la mthode de Gauss-Legendre
double integrale_gauss(double (*func)(double),double a,double b, int n)
{
int j;
double xr,xm,dx,s;

double

*x,*w;

x = (double *)calloc(N,sizeof(double));
w = (double *)calloc(N,sizeof(double));
ploynomes_GaussLegendre(a,b,x,w,n-1); //calcul des poids w et des
abscisses x
xm=0.5*(b+a);
xr=0.5*(b-a);
s=0;
for (j=1;j<N;j++) {
72/82

dx=xr*x[j];
s += w[j]*((*func)(xm+dx)+(*func)(xm-dx));
}
return s *= xr;
delete []x;
delete []w;
}

double
f(double x)
{
// Densit de probabilit de la puissance reue*/
double A = (x-M1)/S;
double B = 1.0/(S*sqrt(2*PI));
return B*exp(-A*A/2.0);
}
int _tmain(int argc, _TCHAR* argv[])
{
double I;
double X0 = -50.0;
double X1 = 0.0;
I = integrale_gauss(f,X0,X1,N);
printf("\n\nI= %18.16g %% \n\n",I*100);
system("pause");
return 0;
}
Lexcution de ce programme donne le rsultat suivant :

Conclusion
Le travail fourni travers ce polycopi a tent de faire un rappel de lalgorithme servant
comme base de calcul sans dmonstration ni calcul derreur. Dautre part, comme nous
pouvons le constater, chaque code jug dlicat et utile est comment et expliqu. Les
exemples que nous avons choisis sont le fruit de notre propre exprience et serviront comme
support de calcul pour dautres cas. Nanmoins, il est fortement recommand de bien
comprendre les routines crites en C avant de plonger dans la programmation quand il sagira
de traiter des cas similaires. En outre, ltudiant doit fournir des efforts et imaginer dautres
solutions et dinnover dans la programmation. Une fonction en C, par exemple, peut tre
crite de plusieurs faons et nous recommandons dallger le code et le rendre claire et lisible
73/82

afin de faciliter son debbogage. Comme dernier conseil, il est toujours plus facile de modifier
un code C dont les fonctions sont spares du main (), il est alors vivement conseill dcrire
dabord les constante fixe (#define N 200 par exemple), les variables globales, les fonctions,
ensuite viendra le main() qui doit ne contenir que les appels aux fonctions. Cest la meilleure
faon de se rendre compte de ses erreurs sans perturber la structure du programme.

74/82

CHAPITRE IV

Rsolution numrique dquations diffrentielles


ordinaires
Mthodes tudies :
Euler Explicite
Euleur Implicite
Runge-Kutta dordre 4

75/82

VI.1. Introduction
Lobjectif de ce chapitre est de rsoudre numriquement des quations diffrentielles du
premier et second degr par la mthode dEuler explicite, Euler implicite et de Runge-Kutta
dordre 4..
VI.2. Rappels mathmatiques
Il sagit de rsoudre une quation diffrentielle du premier degr de la forme :
dy
f x, y , y 0 y 0
dx

VI.2.1. Mthode dEuler explicite


Dans le formalisme de la mthode dEuler explicite on approxime la driv par le schma
suivant :
=
Avec

h = xn+1-xn

Notre quation diffrentielle se rduit la rsolution de la suite suivante :


=

+ (

(E)

Avec la condition initiale y(0)=y0


Lalgorithme de calcul est trs simple. On calcule les yn+1 par le schma de lquation (E)
avec comme condition initiale y(0)=y0.
Exemple 1
Supposons que lon veuille rsoudre lquation diffrentielle suivante :
dy
2 y 1.3e x , y 0 5
dx

Il suffit de choisir h = 0.1 par exemple et les calculs se font de faon direct. Pour ce cas
prcis, f(x,y) = 1.3e-x 2y le schma dEuler se programme trs facilement et le code C cidessous lillustre.

76/82

Code C++ : EULER.CPP


#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
using namespace std;
#define
#define N

h
0.1 // pas h
20 // nombre de points

double f(double x, double y) // la fonction f(x,y)


{
return 1.3*exp(-x) - 2*y;
}
int _tmain(int argc, _TCHAR* argv[])
{
double *x,*y; // tableau xn et yn
x = (double *)calloc(N,sizeof(double));
y = (double *)calloc(N,sizeof(double));
y[0]=5; // valeur initiatle de y(0)
for(int n=0;n<N;n++)
{
x[n] = n*h; // initialisation des abscisses xn
y[n+1] = y[n] +h*f(x[n],y[n]);
cout<<"n="<<n<<"
y["<<n<<"]="<<y[n]<<"\n";
}
return 0;
}
La solution est donn par

77/82

Lalgorithme de Runge Kutta dordre 4 est donn par les quations suivantes

Limplmentation de lexemple prcdent (voir Euler) par la mthode de Runge Kutta en C++
est donne ci-dessous
Code C++ : RUNGE-KUTTA4.CPP
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
using namespace std;
#define
#define N

h
0.1 // pas h
20 // nombre de points

double f(double x,double y) // la fonction f(x,y)


{
return 1.3*exp(-x) - 2*y;
}
int _tmain(int argc, _TCHAR* argv[])
{
double *x,*y; // tableau xn et yn
double k1,k2,k3,k4; // Les 4 variables de Runge-Kutta
x = (double *)calloc(N,sizeof(double));
y = (double *)calloc(N,sizeof(double));
y[0]=5;
for(int n=0;n<N;n++)
{
x[n] = n*h; // initialisation des abscisses xn
k1 = h*f(x[n],y[n]);
78/82

k2 = h*f(x[n]+h/2,y[n]+k1/2);
k3 = h*f(x[n]+h/2,y[n]+k2/2);
k4 = h*f(x[n]+h,y[n]+k3);
y[n+1] = y[n] + (k1+k4)/6 + (k2+k3)/3;
cout<<"n="<<n<<"
y["<<n<<"]="<<y[n]<<"\n";
}
return 0;
}
La solution est donne par ce qui suit

Exercice 2
On se propose de rcrire lquation ci-dessous sous une forme simple de faon pouvoir
utiliser la mthode de Runge-Kutta.
ey

dy
x 2 y 2 2 sin( 3 x), y 0 5
dx

La forme cherche est donc


dy
f ( x, y ), y (0) y 0
dx

Solution
ey

dy
x 2 y 2 2 sin( 3 x), y 0 5
dx

dy 2 sin( 3x ) x 2 y 2

, y 0 5
dx
ey
Dans ce cas nous obtenons
2 sin( 3x ) x 2 y 2
f x, y
ey
79/82

Exercice 3

On se propose de rsoudre un problme classique en physique nuclaire. On considre


lquation de dsintgration dun noyau donne par :
dN
= N
dt
Avec comme condition initiale N(0)=N0
Pour utiliser la mthode Runge-Kutta, il suffit de poser f(x,y)= -y avec la condition initiale
y(0)=N0
La solution est donne par le code C++ ci-dessous
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
using namespace std;
#define
h
0.5 // le pas h
#define N
30 // nombre de points
#define N0 10 // nombre de noyaux t=0
#define lambda 0.5
double f(double x,double y) // la fonction f(x,y)
{
return -lambda*y; // la fonction f(x,y) = - lambnda*y
}
int _tmain(int argc, _TCHAR* argv[])
{
double *x,*y; // tableau xn et yn
double k1,k2,k3,k4; // Les 4 variables de Runge-Kutta
x = (double *)calloc(N,sizeof(double));
y = (double *)calloc(N,sizeof(double));
y[0]=N0;
for(int n=0;n<N;n++)
{
x[n] = n*h; // initialisation des abscisses xn
k1 = h*f(x[n],y[n]);
k2 = h*f(x[n]+h/2,y[n]+k1/2);
k3 = h*f(x[n]+h/2,y[n]+k2/2);
80/82

k4 = h*f(x[n]+h,y[n]+k3);
y[n+1] = y[n] + (k1+k4)/6 + (k2+k3)/3;
cout<<"n="<<n<<"
y["<<n<<"]="<<y[n]<<"\n";
}
return 0;
}

La solution analytique est simple et on peut facilement vrifier notre solution la solution
exacte

Rfrences Bibliographiques
[1] G. Allaire and S. M. Kaber. Algbre linaire numrique. Mathmatiques pour le deuxime
cycle. Ellipses, 2002.
[2] O. Axelsson. Iterative solution methods.Cambridge University Press, 1994.
[3] P. G. Ciarlet. Introduction l'analyse numrique matricielle et l'optimisation _ cours et
exercices corrigs. Mathmatiques appliques pour la matrise. Dunod, 1998.
[4] W. Gautschi. Numerical analysis : an introduction. Birkhuser, 1997.
[5] G. H. Golub and C. F. Van Loan.Matrix computations. Johns Hopkins University
Press,third edition, 1996.
[6] N. J. Higham. Accuracy and stability of numerical algorithms.SIAM, 1996.
[7] E. Isaacson and H. B. Keller.Analysis of numerical methods.Dover, 1994.
81/82

[8] W. H. Press, S. A. Teukolsky, W. T. Veterling, and B. P. Flannery. Numerical recipes: the


artof scientific computing. Cambridge University Press, third edition, 2007.
[9] Matlab est une marque dpose de The MathWorks, Inc., http://www.mathworks.com/.
[10]. GNU Octave est distribu sous licence GNU GPL, http://www.gnu.org/software/octave/.
[11] Wikipedia, the free encyclopedia, http://www.wikipedia.org/.
[12] A. Quarteroni, R. Sacco, and F. Saleri.Mthodes numriques. Algorithmes, analyseet
applications.
Springer, 2007.
[13] J. Stoer and R. Bulirsch.Introduction to numerical analysis. Springer-Verlag, third
edition,
2002.
[14] E. Sli and D. F. Mayers.An introduction to numerical analysis. Cambridge University
Press,
2003.
[15] R. S. Varga. Matrix iterative analysis, volume 27 of Springer series in computational
mathematics.
Springer-Verlag, second edition, 2000.
[16] Numerical Recipes in C, second edition, Cambridge University Press, 1992
W.H. Press, S.A. Teukolski, W.T. Vetterling, B.P. Flannery
Physique numrique, Ed. Vuibert, 1998
P. Depondt
Mthodes de calcul numrique, Ed. Herms, 2001
J.P. Nougier

82/82