Académique Documents
Professionnel Documents
Culture Documents
LANGAGE C
Rappels de Cours, Exercices corrigs, Algorithmes, et leurs Codes C
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.
Mthode de la Bissection,
Mthode de Newton,
Mthode du Point Fixe
Mthode de Lagrange
Mthode de Newton
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
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
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
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.
|<
alors
8/82
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
(1)
(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)
(8)
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
}
1000
12/82
#define
double g(double x)
{
return exp(-x); // fonction test
}
voidmain()
{
double x0,*x;
x = (double *)calloc(N,sizeof(double)); // allocation dynamique
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
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.
break;
}
}
if (err==1) // si on na pas rencontr derreur
{
for (ligne=n-1; ligne>=0; ligne--) // calcul des solutions, en remontant
de la
{
}
}
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
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
( )
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
comatrices(a,c,k,j,n);
= s + powl(-1,k+j)*a[k][j]*det(c,k);
s
}
return(s);
}
{
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;
}
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
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
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
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
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
44/82
0.2
0.4
0.6
0.8
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
49/82
)+
)(
)+ +
)(
)(
Avec
( )=
pour i=0,,n
)+
)(
(
)(
)(
)+
On posera Cn
=
( )
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
"stdafx.h"
<math.h>
<stdlib.h>
<stdio.h>
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;
}
( )=
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>
54/82
{
value += comb(k,m)*y[k-m]*pow(-1.0,m);
m++;
}
while(m<=k);
return value;
}
void
{
}
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;
}
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 :
) ( )avec
=(
)/2
= = ( )/
On obtient alors une succession de rectangles approchant laire sous la courbe.
lim
( )
59/82
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
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
] =1
= 0,6321205
61/82
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
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
] =1
= 0,6321205
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).
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
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
}
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
...
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
<stdio.h>
<stdlib.h>
<math.h>
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
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 :
( )=
)=
( )
S
M1
PI
N
7 // 7 dB cart type
-75.0 // -75 dBm de valeur mdiane
3.141592654
100
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
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
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
h = xn+1-xn
+ (
(E)
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
h
0.1 // pas h
20 // nombre de points
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
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
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
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
82/82