Domanda Risolto Soluzione sistema lineare con Matrice random tra [-1, 1]

alessina02

Utente Bronze
2 Gennaio 2022
35
11
0
25
Poichè il vettore soluzioni è costruito con la somma della riga della matrice coefficienti, le x dovrebbero venire tutte uguali a 1, invece ho in output numeri che sembrano completamente casuali.

C++:
/*Programma che legge una dimensione n minore
di 51 e genera una matrice A con elementi random
tra -1 e 1, costruisce il vettore b con la somma
degli elementi delle righe di A e risolve il sistema
lineare con il metodo di Gauss con riordinamento*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define N 55
int leggi_dato (int&);
int controllo_dato (int);
void m_random (double [N][N], int);
float random (int, int);
void somma_riga (double [N][N], int, double []);
double modulo (double);
void riordinamento_pivotale (int, double [N][N], int, int, double []);
void Gauss (int , double [N][N], double []);
void sostituzione_indietro (int, double [N][N], double [], double []);
int main(){
int n= leggi_dato (n);
double A[N][N];
m_random (A, n);
double b[N];
somma_riga (A, n, b);
for (int r=0; r<n; r++)
    {for (int i=r+1; i<n; i++)
    {riordinamento_pivotale (n, A, i, r, b);}}
Gauss (n, A, b);
double x[N];
sostituzione_indietro (n, A, b, x);
return 0;}


int leggi_dato (int&a)
{printf ("Inserire numero minore di 51="); scanf("%d", &a);
if (controllo_dato (a)==0) {printf ("Numero errato"); return 0;}
return a;}

int controllo_dato (int a)
{if (a>50||a<1) return 0; else return 1;}

void m_random (double a[N][N], int n){
int i, j;
int max=1, min=-1;
srand (time(0));
for (i=0; i<n; i++) {for (j=0; j<n; j++) {{a[i][j]=random (max, min);}
printf ("%.2lf\t", a[i][j]); } printf ("\n");}return;}

float random (int max, int min)
{int z=(rand()%(max-min+1))+min;
float y;
return y=z*rand()/(RAND_MAX*1.0);
}


void somma_riga (double a[N][N], int n, double w[N])
{int i, j, s;
for (i=0; i<n; i++) {w[i]=0; for (j=0; j<n; j++) w[i]=w[i]+a[i][j];}
printf ("\nVettore somma righe A="); for (int k=0; k<n; k++) printf ("%.2lf\t", w[k]);
return;}

double modulo (double a)
{if (a<0) return -a;
else return a; }

void riordinamento_pivotale (int n, double a[N][N], int i, int r, double b[N])
{if (modulo (a[r][r])< modulo (a[i][r])) {for (int h=0; h<n;h++){double temp=a[r][h];
a[r][h]=a[i][h]; a[i][h]=temp; double aux=b[h]; b[h]=b[i]; b[i]=aux;}}
return;}



void Gauss (int n, double a[N][N], double b[N])
{double m;
for (int r=0; r<n; r++)
    {for (int i=r+1; i<n; i++)
            {m=a[i][r]/a[r][r]; a[i][r]=0;
                for(int j=r+1; j<n; j++) {a[i][j]=a[i][j]-a[r][j]*m;}
                b[i]=b[i]-m*b[i];}}
printf ("\nMatrice a scala="); for (int i=0; i<n; i++) {printf ("\n");
for (int j=0; j<n; j++) printf ("\t%.2lf", a[i][j]);
printf ("\t|%.2lf", b[i]);} return;}


void sostituzione_indietro (int n, double L[N][N], double b[], double x[])
{x[n]=b[n]/L[n][n];
for (int i=n-1; i>=0; i--) {x[i]=b[i]; for (int j=i+1; j<n; j++) {x[i]=x[i]-L[i][j]*x[j];} x[i]=x[i]/L[i][i];}
for (int k=0; k<n; k++) {printf ("\nx%d=%.2lf\n", k+1, x[k]); }
}
 
Sta volta proviamo a fare il contrario, io ti posto la soluzione e tu provi a correggere il tuo. Sia qui che negli altri esercizi che hai postato ci sono un sacco di difetti di stile: errori restituiti con return dove (e.g., in leggi_dato) sarebbe meglio usare exit o metterci un while, printf all'interno di funzioni di calcolo, ecc... Ti faccio vedere un codice scritto in modo abbastanza pulito:
C:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define N 51

void print_matrix(double matrix[N][N], size_t size) {
  for (size_t i = 0; i < size; i++) {
    for (size_t j = 0; j < size; j++)
      printf("%.2f\t", matrix[i][j]);
    printf("\n");
  }
}

void print_vector(double matrix[N], size_t size) {
  for (size_t i = 0; i < size; i++)
    printf("%.2f\t", matrix[i]);
  printf("\n");
}

double rand_from_to(double from, double to) {
  return ((double)rand() / RAND_MAX) * (to - from) + from;
}

void rand_matrix(double result[N][N], size_t n) {
  for (size_t i = 0; i < n; i++)
    for (size_t j = 0; j < n; j++)
      result[i][j] = rand_from_to(-1, 1);
}

void sum_row_vect(double result[N], double m[N][N], size_t n) {
  for (size_t i = 0; i < n; i++) {
    result[i] = 0;
    for (size_t j = 0; j < n; j++)
      result[i] += m[i][j];
  }
}

void swap_rows(double matrix[N][N], size_t i, size_t j, size_t n) {
  for (size_t k = 0; k < n; k++) {
    double tmp = matrix[i][k];
    matrix[i][k] = matrix[j][k];
    matrix[j][k] = tmp;
  }
}

void swap_cols(double vector[N], size_t i, size_t j) {
  double tmp = vector[i];
  vector[i] = vector[j];
  vector[j] = tmp;
}

double absval(double x) { return x < 0 ? -x : x; }

int main() {
  srand(time(0));

  size_t n;
  printf("Insert matrix size (up to %d): ", N);
  scanf("%zu", &n);
  if (n > N) {
    fprintf(stderr, "Error: Bad input\n");
    exit(1);
  }

  double matrix[N][N];
  rand_matrix(matrix, n);
  printf("\nMatrix:\n");
  print_matrix(matrix, n);

  double sum[N];
  sum_row_vect(sum, matrix, n);
  printf("\nSum vector:\n");
  print_vector(sum, n);

  /* Pivot partial (row) reorder */
  for (size_t i = 0; i < n - 1; i++) {
    size_t max = i;
    for (size_t j = i + 1; j < n; j++)
      if (absval(matrix[max][i]) < absval(matrix[j][i]))
        max = j;
    if (max != i) {
      swap_rows(matrix, i, max, n);
      swap_cols(sum, i, max);
    }
  }

  printf("\nPivot partial reordering (Matrix):\n");
  print_matrix(matrix, n);
  printf("\nPivot partial reordering (Vector):\n");
  print_vector(sum, n);

  /* Gauss forward */
  for (size_t k = 0; k < n - 1; k++) {
    for (size_t i = k + 1; i < n; i++) {
      double m = matrix[i][k] / matrix[k][k];
      for (int j = k; j < n; j++)
        matrix[i][j] -= m * matrix[k][j];
      sum[i] -= m * sum[k];
    }
  }

  printf("\nGauss forward (Matrix):\n");
  print_matrix(matrix, n);
  printf("\nGauss forward (Vector):\n");
  print_vector(sum, n);

  /* Gauss backwards */
  double x[N];
  x[n - 1] = sum[n - 1] / matrix[n - 1][n - 1];
  for (size_t i = n - 2; i != -1ULL; i--) {
    x[i] = sum[i];
    for (size_t j = i + 1; j < n; j++)
      x[i] -= matrix[i][j] * x[j];
    x[i] /= matrix[i][i];
  }

  printf("\nGauss backwards (Solution):\n");
  print_vector(sum, n);
  printf("\nGauss backwards (Check):\n");
  print_vector(x, n);

  return 0;
}

Ti invito a sistemare il tuo codice e di cercare gli errori senza fare copia e incolla dal mio. Posta la tua soluzione fixata e se non riesci sistemarlo completamente avvisami, poi ti segnalo gli errori che non hai trovato.
 
Ho aggiunto le funzioni di scambio per far girare meglio il riordinamento pivotale, ma non riesco a trovare l'errore nella sostituzione all'indietro. Ho anche provato a partire da n-1, ma stampava 1.#J a tutte le x



C++:
/*Programma che legge una dimensione n minore
di 51 e genera una matrice A con elementi random
tra -1 e 1, costruisce il vettore b con la somma
degli elementi delle righe di A e risolve il sistema
lineare con il metodo di Gauss con riordinamento*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define N 55
int leggi_dato (int&);
int controllo_dato (int);
void m_random (double [N][N], int);
float random (int, int);
void somma_riga (double [N][N], int, double []);
double modulo (double);
void riordinamento_pivotale (int, double [N][N], int, int, double []);
void scambia_riga (int, double[N][N], int, int);
void scambia_colonna (int, double [], int, int);
void Gauss (int , double [N][N], double []);
void sostituzione_indietro (int, double [N][N], double [], double []);
int main(){
int n= leggi_dato (n);
double A[N][N];
m_random (A, n);
double b[N];
somma_riga (A, n, b);
for (int r=0; r<n; r++)
    {for (int i=r+1; i<n; i++)
    {riordinamento_pivotale (n, A, i, r, b);}}
Gauss (n, A, b);
double x[N];
sostituzione_indietro (n, A, b, x);
return 0;}


int leggi_dato (int&a)
{printf ("Inserire numero minore di 51="); scanf("%d", &a);
if (controllo_dato (a)==0) {printf ("Numero errato"); return 0;}
return a;}

int controllo_dato (int a)
{if (a>50||a<1) return 0; else return 1;}

void m_random (double a[N][N], int n){
int i, j;
int max=1, min=-1;
srand (time(0));
for (i=0; i<n; i++) {for (j=0; j<n; j++) {{a[i][j]=random (max, min);}
printf ("%.2lf\t", a[i][j]); } printf ("\n");}return;}

float random (int max, int min)
{int z=(rand()%(max-min+1))+min;
float y;
return y=z*rand()/(RAND_MAX*1.0);
}


void somma_riga (double a[N][N], int n, double w[N])
{int i, j, s;
for (i=0; i<n; i++) {w[i]=0; for (j=0; j<n; j++) w[i]=w[i]+a[i][j];}
printf ("\nVettore somma righe A="); for (int k=0; k<n; k++) printf ("%.2lf\t", w[k]);
return;}

double modulo (double a)
{if (a<0) return -a;
else return a; }

void riordinamento_pivotale (int n, double a[N][N], int i, int r, double b[N])
{if (modulo (a[r][r])< modulo (a[i][r])) {scambia_riga (n, a, r, i); scambia_colonna (n, b, r, i);}
return;}

void scambia_riga (int n, double a[N][N], int r, int i)
{for (int k=0; k<n; k++) {double aux=a[r][k]; a[r][k]=a[i][k]; a[i][k]=aux;}
return;}

void scambia_colonna (int n, double b[N], int r, int i)
{double aux=b[r]; b[r]=b[i]; b[i]=aux; return;
}

void Gauss (int n, double a[N][N], double b[N])
{double m;
for (int r=0; r<n; r++)
    {for (int i=r+1; i<n; i++)
            {m=a[i][r]/a[r][r]; a[i][r]=0;
                for(int j=r+1; j<n; j++) {a[i][j]=a[i][j]-a[r][j]*m;}
                b[i]=b[i]-m*b[i];}}
printf ("\nMatrice a scala="); for (int i=0; i<n; i++) {printf ("\n");
for (int j=0; j<n; j++) printf ("\t%.2lf", a[i][j]);
printf ("\t|%.2lf", b[i]);} return;}


void sostituzione_indietro (int n, double L[N][N], double b[], double x[])
{x[n]=b[n]/L[n][n];
for (int i=n-1; i>=0; i--) {x[i]=b[i]; for (int j=i+1; j<n; j++) {x[i]=x[i]-L[i][j]*x[j];} x[i]=x[i]/L[i][i];}
for (int k=0; k<n; k++) {printf ("\nx%d=%.2lf\n", k+1, x[k]);}
}
 
C:
int leggi_dato(int &);
È sbagliata in quanto non è una sintassi valida in C. Dovresti avere un errore in compilazione perché i tipi reference non esistono in C, ma visto che stai usando un compilatore C++ (i tipi reference esistono in C++) il tuo codice viene compilato comunque. È un errore che ti ho già corretto in passato.

C:
float random(int, int);
È sbagliata per due ragioni. La prima è sottile: esiste già una funzione chiamata random nella libreria standard del C quindi il tuo codice non dovrebbe compilare, ma compila perché stai usando un compilatore C++ e in C++ c'è una feature chiamata overloading che ti permette di fare quello che stai facendo. Dagli un nome diverso. La seconda ragione per cui è sbagliata è nell'implementazione: prima generi un valore casuale intero tra -1 e 1 e poi usi questo valore per generare un float tra -1 e 1. Hai 1/3 di probabilità di generare 0, quindi non stai facendo un estrazione equiprobabile. Un implementazione corretta la trovi nel mio codice nella funzione rand_from_to.

Il riordinamento pivotale ti conviene farlo come l'ho fatto io: prima cerchi l'indice di valore massimo e te lo salvi in una variabile e poi fai lo scambio. Non è necessariamente sbagliato farlo come lo fai tu, ma è inefficiente.

Non riesci a trovare l'errore nella sostituzione in indietro perché l'errore è nella sostituzione in avanti. In Gauss hai sbagliato con gli indici, la versione corretta è:
C:
void Gauss (int n, double a[N][N], double b[N]) {
for (int r=0; r<n-1; r++)
    {for (int i=r+1; i<n; i++)
            {double m=a[i][r]/a[r][r];
                for(int j=r+1; j<n; j++) {a[i][j]=a[i][j]-a[r][j]*m;}
                b[i]=b[i]-m*b[r];}}
printf ("\nMatrice a scala="); for (int i=0; i<n; i++) {printf ("\n");
for (int j=0; j<n; j++) printf ("\t%.2lf", a[i][j]);
printf ("\t|%.2lf", b[i]);}}

Infine, srand(time(0)); andrebbe chiamato una volta sola in tutto il programma. Lo stai già facendo, ma tanto vale metterlo nel main.
 
  • Mi piace
Reazioni: alessina02