Sei sulla pagina 1di 11

Soluzione dei sistemi lineari in C++

Roberto Basili
University of Rome Tor Vergata,
Department of Computer Science, Systems and Production,
00133 Roma (Italy),
basili@info.uniroma2.it

Motivazioni
La seguente dispensa introduce i principi alla base della soluzione con metodi diretti per
la soluzione dei sistemi lineari di n equazioni in n incognite. Inoltre essa fornisce alcune
indicazioni ed esempi per la loro implementazione.
Per una trattazione piu completa degli aspetti analitici di tali metodi si rimanda al
testo Introduzione al Calcolo Numerico, R. Bevilacqua, O. Menchi, ETS, Pisa, 191980.
Per approfondire aspetti algoritmici del problema si consiglia il testo Introduction to
Algorithms, T.H. Cormen, C. E. Leiserson, R.L. Rivest, MIT Press, 1990.

1 Sistemi di Equazioni Lineari


Sia dato un sistema lineare di n equazioni in n variabili della forma

Ax = b (1)

con A = (aij ) i, j = 1, ..., n (detta matrice dei coefficenti ), b = (b1 , ..., bn ) (detto vettore
dei termini noti ) ed x = (x1 , ..., xn ) detto vettore delle soluzioni.

1.1 Metodi Diretti: algoritmo di triangolarizzazione di Gauss


Nel caso particolare in cui nella (1) A = (aij ) assume la forma detta triangolare superiore,
cioe e tale che

aij = 0 j < i

una soluzione diretta alla (1) e data dal vettore x definito nel seguente modo:

xn = bn annP
(2)
xi = (bi nk=i+1 aik xk )/aii , i = n 1, n 2, ..., 2, 1

La equazione (2) e detta sostituzione allindietro 1 .


Il metodo di Gauss consiste nel portare un generico sistema Ax = b in una forma
equivalente U x = b0 in cui U assume una forma triangolare superiore, che mediante la
applicazione della (2) possa essere risolto direttamente.
La tecnica utilizzata e qualla di generare una successione di sistemi lineari tutti tra
loro equivalenti, e cioe una successione di matrici quadrate A(k) ,

A = A(1) A(2) ... A(n1) A(n) = U

ed equivalentemente vettori dei termini noti b(k) ,


1
Osserviamo che per ipotesi il sistema ammette soluzioni, quindi aii 6= 0 i.

1
b = b(1) b(2) ... b(n1) b(n) = b0
tali che:
A(k) x = b(k) k = 1, ..., n

1.1.1 Generazione della successione dei Sistemi


(k+1) (k) (k)
aij = aij mik akj , i = k + 1, k + 2, ..., n; j = k, k + 1, ..n
(k+1) (k) (k)
bi = bi mik bk i = k + 1, k + 2, ..., n; j = k, k + 1, ..n
I numeri mik (detti moltiplicatori della fase k-esima sono definiti da
(k)
aik
mik = (k)
, i = k + 1, k + 2, ..., n
akk

1.1.2 Casi particolari


Sistemi indeterminati a causa di una dipendenza lineare tra righe
Selezione dellelemento moltiplicatore, pivot.

1.2 Implementazione del Programma C++


1.2.1 Variabili del Programma e Strutture dei dati.
Nella implementazione in C++ del metodo sono necessari le seguenti variabili
un array bidimensionale per la rapprsentazione della matrice quadrata A
due vettori unidimensionali per la rappresentazione dei termini noti e delle soluzioni,
b ed x rispettivamente
variabili ausiliarie per la rappresentazione di informazioni complementari, per es-
empio lo stato di del programma al termine della esecuzione (nei casi particolari
evidenziati di sopra) o variabili di interazione con lutente
La seguente rappresentazione
const int MAX_DIM = 10;
...

main()
{
double A[MAX_DIM][MAX_DIM], // matrice coefficenti
B[MAX_DIM], // matrice termini noti
X[MAX_DIM]; // vettore soluzioni

int dim; // dimensione richiesta dal sistema corrente


distingue:
una costante MAX DIM che costituisce lordine massimo del sistema (cioe il massimo
numero di equazioni gestite dal programma
la variabile dim che rappresenta la dimensione del sistema corrente ed e aggior-
nata su richiesta dellutente, determinando la porzione di array utilizzato durante
lesecuzione di quel sistema
larray di double A che rappresenta di volta in volta i coefficenti della matrice del
sistema
gli array X e B che contengono le soluzioni e i termini noti, rispettivamente

2
1.2.2 Calcolo delle soluzioni allindietro

x[dim]=b[dim]/A[dim][dim]; // n-esima equazione

for(i=dim-1; i>=0; i--) {

temp = b[i];
for( k=i+1; k<dim; k++)
temp=temp-A[i][k]*sol[k];

x[i] = temp/A[i][i];

} // for sulle righe n-1,n-2, ..., 1

3
1.2.3 Struttura del programma principale
main()
{
double A[MAX_DIM][MAX_DIM], // matrice coefficenti
B[MAX_DIM], // matrice termini noti
X[MAX_DIM]; // vettore soluzioni

int dim; // dimensione richiesta da sistema corrente


int success; // variabile di ritorno dala procedura Gauss()
// success==0 => trovate soluzioni
// success==1 => non trovate soluzioni
char resp = y;

do{
system("cls"); cout << "\n\n\n";
// leggi matrice ingresso
leggi(A, dim);

// Leggi vettore termini noti


leggi_tn( dim, B);

//stampa il sistema
stampa(A,B,dim);

// Gauss() per la soluzione


success=gauss(A,B,X,dim);

// stampa dei risultati


if ( success==0 ) {
cout << "\n\nLa Matrice Triangolare superiore e:\n";
stampa(A,B,dim);
cout << "\n\nIl vettore delle soluzioni e:\n";
stampa_sol(X,dim);
} else cout << "Il sistema e indeterminato.\n\n";

cout << "\n\n ======== ? Vuoi continuare (y/n) ? >>> "; cin >> resp;
} while( resp == y || resp == Y );

} // main()

1.2.4 Triangolarizzazione della matrice e calcolo delle soluzioni


int gauss( double coef_mat[MAX_DIM][MAX_DIM], // matrice dei coefficenti
double term_noti[MAX_DIM], // vettore termini noti
double sol[MAX_DIM], // vettore delle soluzioni in uscita
int dim) // dimensione del sistema
{
int i, j, k, // indici di scansione della matrice
check = 0;
double piv, alfa, temp;

for( j=0; j<dim-1; j++)


{
// scegli pivot di colonna j;
check = pivot(dim, j, coef_mat, term_noti);
if( check == 0 )
piv=coef_mat[j][j];
else
return(-1);

4
// combinazione lineare delle righe al di sotto della i-esima
for( i=j+1;i<dim; i++) {

// calcolo del coefficente della combinazione lineare


alfa = coef_mat[i][j]/piv;

// sottrazione
for( k=j; k<dim; k++)
coef_mat[i][k]=coef_mat[i][k]-alfa*coef_mat[j][k];

// trattamento dei termini noti


term_noti[i]=term_noti[i]-alfa*term_noti[j];
} // for su righe i da j+1 a n

} //for sui primi n-1 elemnti della diagonale a[j][j]

// Check sulla indipendenza dellultima riga,


// cioe se il determinante (prodotto degli elementi della diagonale principale,
// e diverso da 0
if( coef_mat[dim-1][dim-1] == 0) {
cout << "Righe linearmente dipendenti. Soluzioni infinite\n\n";
return(1);
}

//Trovo ora la soluzione


sol[dim]=term_noti[dim]/coef_mat[dim][dim];
for(i=dim-1; i>=0; i--) {
temp = term_noti[i];
for( k=i+1; k<dim; k++)
temp=temp-coef_mat[i][k]*sol[k];
sol[i] = temp/coef_mat[i][i];
} // for sulle righe n-1,n-2, ..., 1

return(0);

}// gauss()

1.2.5 Funzione di pivoting


// Funzione di pivoting parziale;
// cerca il pivot per la colonna j-esima
// e se diverso da a[j][j] esegue lo scambio
int pivot( int dim, //dimensione
int j, // indice di colonna
double matr[MAX_DIM][MAX_DIM], // matrice coefficenti
double tn[MAX_DIM]) // termini noti
{
int k,r;
double temp;
char cont;

//for( k=j; matr[k,j]==0 & k<=dim; k++);


system("cls");

cout << " Pivoting: passo (" << j << ")\n";


stampa(matr,tn, dim);
system("PAUSE");

5
// cerco il primo elemento non nullo
k=j;
while( k<dim && matr[k][j]==0 ) ++k;

if( k<dim ) // esiste k tc matr[k,j]==0


cout << "matr[j][j] non nullo per j=" << k+1 << "\n";
else {
cout << "Pivot NULLO !!\n\n";
return(-1);
}

if( k!=j ) {
cout << "Scambio Riga " << j << " con " << k << "\n";
// scambio righe
for( r=j; r<dim; r++ )
{
temp = matr[j][r];
matr[j][r] = matr[k][r];
matr[k][r] = temp;
}
temp = tn[j];
tn[j] = tn[k];
tn[k] = temp;
}
return(0);

} // pivot()

1.2.6 Esempio di esecuzione del programma


Se il sistema Ax = b e dato da

| 1 1 1 1 |
| 1 2 1 1 |
A = | 1 1 3 1 |
| 1 1 1 4 |

| 1 |
b = | 2 |
| 3 |
| 4 |

Il programma dovrebbe produrre il seguente risultato:


Pivoting: passo (0)
Matrice
a(1,1)=1 a(1,2)=1 a(1,3)=1 a(1,4)=1
a(2,1)=1 a(2,2)=2 a(2,3)=1 a(2,4)=1
a(3,1)=1 a(3,2)=1 a(3,3)=3 a(3,4)=1
a(4,1)=1 a(4,2)=1 a(4,3)=1 a(4,4)=4

Pivoting: passo (1)


Matrice
a(1,1)=1 a(1,2)=1 a(1,3)=1 a(1,4)=1

6
a(2,1)=0 a(2,2)=1 a(2,3)=0 a(2,4)=0
a(3,1)=0 a(3,2)=0 a(3,3)=2 a(3,4)=0
a(4,1)=0 a(4,2)=0 a(4,3)=0 a(4,4)=3

Pivoting: passo (2)


Matrice
a(1,1)=1 a(1,2)=1 a(1,3)=1 a(1,4)=1
a(2,1)=0 a(2,2)=1 a(2,3)=0 a(2,4)=0
a(3,1)=0 a(3,2)=0 a(3,3)=2 a(3,4)=0
a(4,1)=0 a(4,2)=0 a(4,3)=0 a(4,4)=3

La Matrice Triangolare superiore e:


Matrice
a(1,1)=1 a(1,2)=1 a(1,3)=1 a(1,4)=1
a(2,1)=0 a(2,2)=1 a(2,3)=0 a(2,4)=0
a(3,1)=0 a(3,2)=0 a(3,3)=2 a(3,4)=0
a(4,1)=0 a(4,2)=0 a(4,3)=0 a(4,4)=3

Il vettore delle soluzioni e:


Vettore soluzioni
x(1)=-2
x(2)=1
x(3)=1
x(4)=1

7
A Programma completo per lapplicazione del metodo di
Gauss
per la soluzione dei sistemi lineari
#include <iostream.h>
#include <math.h>
#include <iomanip.h>
#include <stdlib.h>

const int MAX_DIM = 10;

// struct matrix {

void leggi( double matr[MAX_DIM][MAX_DIM], int &dim);

void leggi_tn( int dimensione, double tn[]);

int pivot( int dim, int j, double matr[MAX_DIM][MAX_DIM], double tn[MAX_DIM]);

void stampa(double matr[MAX_DIM][MAX_DIM], double term_noti[MAX_DIM], int dim);

int gauss( double coef_mat[MAX_DIM][MAX_DIM], double term_noti[MAX_DIM],


double sol[MAX_DIM], int dim)
{
int i, j, k, // indici di scansione della matrice
check = 0;
double piv, alfa, temp;

for( j=0; j<dim-1; j++)


{
// scegli pivot;
check = pivot(dim, j, coef_mat, term_noti);
if( check == 0 )
piv=coef_mat[j][j];
else
return(-1);

// combinazione lineare
for( i=j+1;i<dim; i++) {
// calcolo del coefficente della combinazione lineare
alfa = coef_mat[i][j]/piv;
// sottrazione
for( k=j; k<dim; k++)
coef_mat[i][k]=coef_mat[i][k]-alfa*coef_mat[j][k];

// termini noti
term_noti[i]=term_noti[i]-alfa*term_noti[j];
} // for su righe i da j+1 a n

} //for sui primi n-1 elemnti della diagonale a[j][j]

// Check su determinante
if( coef_mat[dim-1][dim-1] == 0) {
cout << "Righe linearmente dipendenti. Soluzioni infinite\n\n";
return(1);
}

//Trovo ora la soluzione

8
sol[dim]=term_noti[dim]/coef_mat[dim][dim];
for(i=dim-1; i>=0; i--) {
temp = term_noti[i];
for( k=i+1; k<dim; k++)
temp=temp-coef_mat[i][k]*sol[k];
sol[i] = temp/coef_mat[i][i];
} // for sulle righe n-1,n-2, ..., 1

return(0);

}// gauss()

// Funzione di pivoting parziale;


// cerca il pivot per la colonna j-esima
// e se diverso da a[j][j] esegue lo scambio
int pivot( int dim, int j, double matr[MAX_DIM][MAX_DIM], double tn[MAX_DIM])
{
int k,r;
double temp;
char cont;

//for( k=j; matr[k,j]==0 & k<=dim; k++);


system("cls");

cout << " Pivoting: passo (" << j << ")\n";


stampa(matr,tn, dim);
system("PAUSE");

// cerco il primo elemento non nullo


k=j;
while( k<dim && matr[k][j]==0 ) ++k;

if( k<dim ) // esiste k tc matr[k,j]==0


cout << "matr[j][j] non nullo per j=" << k+1 << "\n";
else {
cout << "Pivot NULLO !!\n\n";
return(-1);
}

if( k!=j ) {
cout << "Scambio Riga " << j << " con " << k << "\n";
// scambio righe
for( r=j; r<dim; r++ )
{
temp = matr[j][r];
matr[j][r] = matr[k][r];
matr[k][r] = temp;
}
temp = tn[j];
tn[j] = tn[k];
tn[k] = temp;
}
return(0);

} // pivot()

9
void leggi( double matr[MAX_DIM][MAX_DIM], int &dim)
{
int i,j;

cout << "Inserire la dimensione: "; cin >> dim;

for( i=0; i<dim; i++)


for( j=0; j<dim; j++) {
cout << "a(" << i+1 << "," << j+1 << ")="; cin >> matr[i][j];
}
}

void leggi_tn( int dim, double tn[MAX_DIM])


{
int i;

for( i=0; i<dim; i++) {


cout << "b(" << i+1 << ")="; cin >> tn[i];
}
}

void stampa(double matr[MAX_DIM][MAX_DIM], double term_noti[MAX_DIM], int dim)


{
int i,j;

cout << "Matrice\n";


for( i=0; i<dim; i++) {
for( j=0; j<dim; j++)
cout << "\ta("
<< i+1 << ","
<< j+1 << ")="
<< setprecision(3) << matr[i][j];
cout << "\n";
}
}

void stampa_sol(double sol[MAX_DIM], int dim)


{
int i;

cout << "Vettore soluzioni\n";


for( i=0; i<dim; i++) {
cout << "\tx(" << i+1 << ")=" << setprecision(3) << sol[i];
cout << "\n";
}
} // stampa_sol()

main()
{
double A[MAX_DIM][MAX_DIM], // matrice coefficenti
B[MAX_DIM], // matrice termini noti
X[MAX_DIM]; // vettore soluzioni

int dim; // dimensione richiesta da sistema corrente


int success; // variabile di ritorno dala procedura Gauss()
// success==0 => trovate soluzioni
// success==1 => non trovate soluzioni
char resp = y;

10
do{
system("cls"); cout << "\n\n\n";
// leggi matrice ingresso
leggi(A, dim);

// Leggi vettore termini noti


leggi_tn( dim, B);

//stampa il sistema
stampa(A,B,dim);

// Gauss() per la soluzione


success=gauss(A,B,X,dim);

// stampa()
if ( success==0 ) {
cout << "\n\nLa Matrice Triangolare superiore e:\n";
stampa(A,B,dim);
cout << "\n\nIl vettore delle soluzioni e:\n";
stampa_sol(X,dim);
} else cout << "Il sistema e indeterminato.\n\n";

cout << "\n\n ======== ? Vuoi continuare (y/n) ? >>> "; cin >> resp;
} while( resp == y || resp == Y );

} // main()

11