Buscar

Determinante e Inversa - Eliminação de Gauss - Fatoração LU - Gauss Jacobi e Seidel (C++).

Esta é uma pré-visualização de arquivo. Entre para ver o arquivo original

Leia-me - Como carregar uma matriz por arquivo.txt
Para escrever sistema linear em um arquivo de formato .txt basta digitar os coeficientes da matriz do sistema. 
Siga o exemplo:
Você tem o seguinte sistema linear:
2 x1 + 5 x2 + 3 x3 = 19
1 x1 + 4 x2 + 2 x3 = 15
7 x1 + 1 x2 + 6 x3 = 27
Seu arquivo .txt deve ter a seguinte informação (somente os coeficientes):
2 5 3 19
1 4 2 15
7 1 6 27
Determinante e Inversa.c
//Calculo do determinante e da inversa de uma matriz quadrada qualquer
//Luiz Vinicius Soglia - lvmsoglia@hotmail.com
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
//==========================================================================================================
 
// Função para calcular o Determinante e a Inversa de uma matriz
//n é a ordem da matriz que se deseja calcular o determinante e a inversa
//mA é a matriz que se deseja calcular
//mI é uma matriz que guardará a matriz inversa ao final da execução da função, caso exista inversa (det diferente de zero)
float det_inversa (int n, float mA[][n], float mI[][n])
{ 
 int i, j, k, posl, erro;
 float det, aux, pivo, m;
 
 //Constroi a matriz identidade [mI] para ser usada no calculo da inversa
 for (i=0; i<n; i++)
 {
 for (j=0; j<n; j++)
 {
 if (i==j)
 {mI[i][j] = 1.0;} //diagonal principal
 else
 {mI[i][j] = 0.0;}
 }
 }
 
 det=1.0; //det inicialmente guarda as trocas de sinal do determinante, caso haja mudanças de linhas no pivoteamento parcial
 erro = 0; //A variavel erro se tornara 1 caso haja erros de divisao por zero
 
 //pivoteamento parcial e Metodo da eliminacao de Gauss (Triangularizacao superior)
 for (k=0; k<(n-1); k++)
 { 
 
 pivo=fabs(mA[k][k]); //pivo inicial
 posl=k; //posicao da linha do pivo
 for (i=k+1; i<n; i++)
 {
 if (fabs(mA[i][k])>pivo)
 {
 pivo=fabs(mA[i][k]); //passa a ser o novo pivo
 posl=i; //guardam a posicao (linha e coluna) do maior pivo
 }
	 }
	 
 if (posl!=k) //caso o pivo nao esteja na linha k, troca linha k pela linha posl
 {
 for (j=k; j<n; j++)
 {
	 aux=mA[k][j];
	 mA[k][j]=mA[posl][j];
	 mA[posl][j]=aux;
 }
 //tambem faz as mesmas operacoes na matriz identidade
 for (j=0; j<n; j++)
 {
 aux=mI[k][j];
	 mI[k][j]=mI[posl][j];
	 mI[posl][j]=aux;
 }
 if ((posl-k)%2 != 0) //se for um numero impar de diferença entre as linhas
 {det = det*(-1);} //com a troca de linhas, o determinante muda de sinal, det guarda o sinal do determinante
 }
	 
	 //Metodo da eliminacao de Gauss (Triangularizacao superior)
	 if (mA[k][k] != 0) //Evita erros de divisao por zero
	 {
 for (i=k+1; i<n; i++)
 {
 m = mA[i][k]/mA[k][k]; //calcula o multiplicador
 mA[i][k] = 0.0; //agora assume zero para o valor a ser zerado, afim de poupar tempo
 for (j=k+1; j<n; j++) //comeca do elemento apos o valor a ser zerado
 {
 mA[i][j] = mA[i][j] - (m*mA[k][j]);
 }
 //tambem faz as mesmas operacoes na matriz identidade
 for (j=0; j<n; j++)
 {
 mI[i][j] = mI[i][j] - (m*mI[k][j]);
 }
 }
 }
 else
 {erro = 1; break;} //Houve erro de divisão por zero - todos os pivôs são zero
 
 } //fim do pivoteamento parcial e Metodo da eliminacao de Gauss (Triangularizacao superior)
 if (erro == 1) //Houve erro de divisao por zero - um dos pivos é igual a zero e com isso det sera zero
 {return 0.0;}
 
 //Calcula o det. Como a matriz agora eh triangular superior, o det sera o produto dos elementos da diagonal principal
 for (k=0; k<n; k++)
 {det = det * mA[k][k];}
 
 if (det == 0.0)
 {return 0.0;}
 
 //calcula a inversa - faz uma triangularizacao inferior para tornar a matriz [mA] uma matriz diagonal e depois identidade
 //mas esses passos só serão aplicados em [mI], que guardara a matriz inversa ao final dos passos
 for (k=n-1; k>0; k--)
 {
 if (mA[k][k] != 0) //Evita erros de divisao por zero
	 {
 for (i=k-1; i>=0; i--)
 {
 m = mA[i][k]/mA[k][k]; //calcula o multiplicador
 for (j=0; j<n; j++)
 {
 mI[i][j] = mI[i][j] - (m*mI[k][j]);
 }
 } 
 }
 else
 {erro = 1; break;} //Houve erro de divisão por zero - um elemento da diagonal principal eh igual a zero
 }
 if (erro == 1)
 {return 0.0;}
 
 //finaliza dividindo a matriz [pelos elementos da diagonal principal, ultimo passo para transforma-la em matriz inversa
 for (i=0; i<n; i++)
 {
 for (j=0; j<n; j++)
 {
 mI[i][j] = mI[i][j]/mA[i][i];
 }
 }
 
 return det;
}
//==========================================================================================================
//Função principal
int main()
{
 int n, i, j, carregamento;
 char op, nome_arq[260];
 float det;
 FILE *fp;
 do
 {
 printf ("Calculo do Determinate e da Inversa de uma matriz quadrada [A] qualquer\n\n"); 
 do
 {
 printf ("Digite a ordem da matriz quadrada (n), no maximo n=100: ");
 fflush(stdin); scanf ("%d",&n);
 }
 while (n < 2 || n > 100);
 
 printf ("\nDigite a opcao para o carregamento do sistema linear:\n\n[1] Digitar os dados aqui\n[2] Atraves de um arquivo .txt\n\n");
 do
 {
 printf ("Opcao: ");
 fflush(stdin); scanf ("%d",&carregamento);
 }
 while (carregamento < 1 || carregamento > 2);
 
 //Cria as matrizes
 float mA[n][n], mI[n][n]; //cria a matriz [mA] e uma matriz que guardara a sua inversa [mI]
 
 //faz o carregamento da matriz [mA] de acordo com a opcao escolhida
 switch (carregamento)
 {
 
 case 1: //digita a matriz
 for (i=0; i<n; i++)
 {
 do
 {
 system ("cls");
 printf ("Digite os elementos da linha %d:\n\n", i+1); 
 for (j=0; j<n; j++)
 { 
 printf ("a[%d][%d] = ", i+1, j+1);
 scanf ("%f", &mA[i][j]);
 }
 printf ("\nOs valores digitados estao corretos? (digite [S] para sim, ou [N] para nao): ");
 fflush(stdin); op = getchar();
 }
 while (op != 's' && op != 'S');
 }
 break;
 
 case 2: //carrega do arquivo
 do
 {
 printf ("\nDigite o caminho (com a extensao) do arquivo de texto com os dados:\n");
 fflush(stdin);
 scanf ("%259[^\n]",nome_arq);
 fp=fopen(nome_arq,"r");
 if (!fp)
 {
 printf ("\nErro na abertura do arquivo! Pressione [ENTER] para continuar\n");
 fflush(stdin); op = getchar();
}
 }
 while(!fp);
 //inicializa e lê os coeficientes da matriz mA
 for (i=0; i<n; i++)
 {
 for (j=0; j<n; j++)
 { 
 mA[i][j]=0.0;
 fscanf (fp, "%f", &mA[i][j]);
 }
 }
 fclose(fp);
 break;
 
 default: 
 printf ("\nOcorreu um erro! Pressione [ENTER] para sair\n"); fflush(stdin); op = getchar(); return 0;
 
 } //fim do carregamento da matriz
 
 system ("cls");
 printf ("Dados carregados com sucesso!\nPressione [ENTER] para continuar e calcular o Determinante e a Inversa\n");
 fflush(stdin); op = getchar(); system ("cls");
 
 //Chama a funcao que calcula o determinante e a inversa da matriz 
 det = det_inversa (n, mA, mI);
 
 if (det == 0.0) //se det igual a zero a matriz nao possui inversa
 {printf ("Determinante (det A) = 0\nA matriz A nao possui inversa!\n\nPressione [ENTER] para sair\n"); op = getchar(); return 0;}
 
 printf ("Determinante (det A) = %f\n\nDeseja visualizar a Inversa da matriz? Digite [S] para sim, ou [N] para nao: ", det);
 fflush(stdin); op = getchar(); fflush(stdin);
 if (op == 's' || op == 'S')
 {
 //cria o arquivo de texto .txt para escrita
 if ((fp = fopen ("MATRIZ_INVERSA.txt", "w")) == NULL)
 {printf ("\nErro ao salvar a matriz inversa em um arquivo!\n\nPressione [ENTER] para sair!\n"); op = getchar(); return 0;}
 
 //imprime a matriz inversa no arquivo de texto .txt
 for (i=0; i<n; i++)
 {
 for (j=0; j<n; j++)
 {
 fprintf (fp, "%f ", mI[i][j]);
 }
 fprintf (fp, "\n");
 }
 fclose (fp);
 
 //abre o arquivo com o resultado para o usuario visualizar
 system ("start MATRIZ_INVERSA.txt");
 }
 
 printf ("\nDeseja reiniciar o programa? (digite [S] para sim, ou [N] para nao): ");
 fflush(stdin); op = getchar(); system ("cls");
 }
 while (op == 's' || op == 'S');
 return 0; 
}
Eliminacao de Gauss.c
//Resolucao de sistemas lineares utilizando o metodo da eliminacao de Gauss
//Luiz Vinicius Soglia - lvmsoglia@hotmail.com
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
//==========================================================================================================
//troca na str o caractere ca pelo caractere cb
void troca_caractere (char *str, const char ca, const char cb)
{
 int n, i;
 n = strlen(str);
 for (i=0; i<n; i++)
 {
 if (str[i] == ca)
 {str[i] = cb;}
 }
}
//==========================================================================================================
//funcao que implementa a resolução de sistemas lineares pela eliminação de Gauss e retrossubstituição.
//n: é a ordem do sistema.
//metodo: guarda o método a ser utilizado para a resulução: 1 = sem pivoteamento, 2 = pivoteamento parcial, 3 = pivoteamento total.
//matriz a[][]: é a matriz dos coeficientes.
//matriz b[]: é a matriz dos termos independentes.
//matriz x[]: guarda os valores das variaveis após a resolução.
//matriz o[] guarda a coluna correspondente a cada variavel, pois no pivoetamento total pode ocorrer troca de colunas.
//retorna 0 caso haja sucesso, 1 para erros de entrada de argumentos invalidos, e 2 para erros de divisão por zero.
int eliminacao_gauss (int n, int metodo, float a[][n], float b[], float x[], int o[])
{
 int k, i, j, posl, posc, erro;
 float m, soma, aux, pivo;
 if (n<2)
 {return 1;} //a ordem do sistema tem que ser maior ou igual a 2
 
 for (i=0; i<n; i++) //inicializa as variaveis x (por precaução) e o vetor ordem das variaveis x
 {x[i]=0; o[i]=i+1;}
 erro = 0; //A variavel erro se tornara 1 caso haja erros de divisao por zero
 switch (metodo) //triangulariza a matriz do sistema linerar de acordo com o metodo escolhido
 {
 //sem pivoteamento =====================================================
 case 1:
 for (k=0; k<(n-1); k++)
 {
	 //Metodo da eliminacao de Gauss (Triangularizacao)
	 if (a[k][k] != 0.0) //Evita erros de divisao por zero
	 {
 for (i=k+1; i<n; i++)
 {
 m = a[i][k]/a[k][k]; //calcula o multiplicador
 a[i][k] = 0.0; //agora assume zero para o valor a ser zerado, afim de poupar tempo
 for (j=k+1; j<n; j++) //comeca do elemento apos o valor a ser zerado
 {
 a[i][j] = a[i][j] - (m*a[k][j]);
 }
 b[i] = b[i] - m*b[k];
 }
	 }
 else
 {erro = 1; break;} //Houve erro de divisão por zero
 }
 break;
 //pivoteamento parcial =================================================
 case 2:
 for (k=0; k<(n-1); k++)
 {
 pivo=fabs(a[k][k]); //pivo inicial
 posl=k; //posicao da linha do pivo
 for (i=k+1; i<n; i++)
 {
 if (fabs(a[i][k])>pivo)
 {
 pivo=fabs(a[i][k]); //passa a ser o novo pivo
 posl=i; //guarda a posicao da linha do maior pivo
 }
 }
 if (posl!=k) //caso o pivo nao esteja na linha k, troca linha k pela linha posl
 {
 for (j=k; j<n; j++) //comeca a troca dos elementos apos os elementos zerados
 {
 aux=a[k][j];
 a[k][j]=a[posl][j];
	 a[posl][j]=aux;
 }
 aux=b[k];
 b[k]=b[posl];
 b[posl]=aux;
 }
 //Metodo da eliminacao de Gauss (Triangularizacao)
	 if (a[k][k] != 0.0) //Evita erros de divisao por zero, caso o pivo seja zero
	 {
 for (i=k+1; i<n; i++)
 {
 m = a[i][k]/a[k][k]; //calcula o multiplicador
 a[i][k] = 0.0; //agora assume zero para o valor a ser zerado, afim de poupar tempo
 for (j=k+1; j<n; j++) //comeca do elemento apos o valor a ser zerado
 {
 a[i][j] = a[i][j] - (m*a[k][j]);
 }
 b[i] = b[i] - m*b[k];
 }
 }
 else
 {erro = 1; break;} //Houve erro de divisão por zero
 }
 break;
 //pivoteamento total ===================================================
 case 3:
 for (k=0; k<(n-1); k++)
 {
 pivo=fabs(a[k][k]); //pivo inicial
 posl=k; //posicao da linha do pivo
 posc=k;//posicao da coluna do pivo
 for (i=k; i<n; i++)
 {
 for (j=k; j<n; j++)
	 {
 if (fabs(a[i][j])>pivo)
	 {
 pivo=fabs(a[i][j]); //passa a ser o novo pivo
	 //guardam a posicao (linha e coluna) do maior pivo
	 posl=i;
	 posc=j;
 }
	 }
	 }
 if (posl!=k) //caso o pivo nao esteja na linha k, troca linha k pela linha posl
 {
 for (j=k; j<n; j++) //comeca a troca dos elementos apos os elementos zerados
 {
 aux=a[k][j];
 a[k][j]=a[posl][j];
	 a[posl][j]=aux;
 }
 aux=b[k];
	 b[k]=b[posl];
	 b[posl]=aux;
}
 if (posc!=k) //caso o pivo nao esteja na coluna k, troca coluna k pela coluna posc
 {
 for (j=0; j<n; j++)
 {
	 aux=a[j][k];
 a[j][k]=a[j][posc];
 a[j][posc]=aux;
 }
 //como houve troca de coluna, atualiza o vetor que guarda a ordem das incognitas x
 aux=o[k];
	 o[k]=o[posc];
	 o[posc]=aux;
 }
	 //Metodo da eliminacao de Gauss (Triangularizacao)
	 if (a[k][k] != 0.0) //Evita erros de divisao por zero
	 {
 for (i=k+1; i<n; i++)
 {
 m = a[i][k]/a[k][k]; //calcula o multiplicador
 a[i][k] = 0.0; //agora assume zero para o valor a ser zerado, afim de poupar tempo
 for (j=k+1; j<n; j++) //comeca do elemento apos o valor a ser zerado
 {
 a[i][j] = a[i][j] - (m*a[k][j]);
 }
 b[i] = b[i] - m*b[k];
 }
	 }
 else
 {erro = 1; break;} //Houve erro de divisão por zero
 }
 break;
 //Caso não exista a opção de método passada para a função, implica em erro. Retorna 1, indicando esse erro.
 default:
 return 1;
 } //fim do switch-case com os metodos de triangularizacao
 if (erro == 1) //Houve erro de divisão por zero. Retorna 2, indicando esse erro.
 {return 2;}
 //Caso não haja erros na eliminação de Gauss, aplica o Metodo de resolucao de sistemas triangulares (Retrosubstituicao)
 if (a[n-1][n-1] != 0.0)
 {x[n-1] = b[n-1] / a[n-1][n-1];}
 else
 {return 2;} //antes atribuia zero a variavel: {x[n-1] = 0.0;}, mas achei melhor retornar o erro como uma divisão por zero
 for (i=n-2; i>-1; i--)
 {
 soma = 0.0;
 for (j=i+1; j<n; j++)
 {soma = soma + a[i][j]*x[j];}
 if (a[i][i] != 0)
 {x[i] = (b[i] - soma)/a[i][i];}
 else
 {return 2;} //antes atribuia zero a variavel: {x[i] = 0.0;}, mas achei melhor retornar o erro como uma divisão por zero
 }
 return 0;
}
//==========================================================================================================
//Função principal
int main()
{
 int n, i, j, metodo, carregamento, teste;
 char op, nome_arq[260], buffer[64];
 FILE *fp;
 do
 {
 printf ("Resolucao de sistemas lineares utilizando o metodo da eliminacao de Gauss\n\n");
 do
 {
 printf ("Digite a ordem do sistema (n), no maximo n=100: ");
 fflush(stdin); scanf ("%d",&n);
 }
 while (n < 2 || n > 100);
 printf ("\nDigite a opcao do metodo de pivoteamento:\n\n[1] Sem pivoteamento\n[2] Pivoteamento parcial\n[3] Pivoteamento total\n\n");
 do
 {
 printf ("Opcao: ");
 fflush(stdin); scanf ("%d",&metodo);
 }
 while (metodo < 1 || metodo > 3);
 printf ("\nDigite a opcao para o carregamento do sistema linear:\n\n[1] Digitar os dados aqui\n[2] Atraves de um arquivo .txt\n\n");
 do
 {
 printf ("Opcao: ");
 fflush(stdin); scanf ("%d",&carregamento);
 }
 while (carregamento < 1 || carregamento > 2);
 //Cria as matrizes
 float a[n][n], x[n], b[n]; //cria as matrizes dos coeficientes (A), das variaveis (X) e dos termos independentes (B)
 int o[n]; //vetor que guarda a ordem das incognitas x
 //faz o carregamento da matriz do sistema de acordo com a opcao escolhida
 switch (carregamento)
 {
 case 1: //digita a matriz
 for (i=0; i<n; i++)
 {
 do
 {
 system ("cls");
 printf ("Digite os elementos da linha %d:\n\n", i+1);
 for (j=0; j<n; j++)
 {
 printf ("a[%d][%d] = ", i+1, j+1);
 scanf ("%f", &a[i][j]);
 }
 printf ("\nb[%d] = ", i+1);
 scanf ("%f", &b[i]);
 printf ("\nOs valores digitados estao corretos? (digite [S] para sim, ou [N] para nao): ");
 fflush(stdin); op = getchar();
 }
 while (op != 's' && op != 'S');
 }
 break;
 case 2: //carrega do arquivo
 do
 {
 printf ("\nDigite o caminho do arquivo de texto (com a extensao) que contem os dados:\n");
 fflush(stdin);
 scanf ("%259[^\n]",nome_arq);
 fp=fopen(nome_arq,"r");
 if (!fp)
 {
 printf ("\nErro na abertura do arquivo! Pressione [ENTER] para continuar\n");
 fflush(stdin); op = getchar();
 }
 }
 while(!fp);
 //inicializa e lê os coeficientes das matrizes A e B
 for (i=0; i<n; i++)
 {
 for (j=0; j<n; j++)
 {
 a[i][j]=0.0;
 fscanf (fp, "%f", &a[i][j]);
 }
 b[i]=0.0;
 fscanf (fp, "%f", &b[i]);
 }
 fclose(fp);
 break;
 default:
 printf ("\nOcorreu um erro no carregamento do sistema! Pressione [ENTER] para sair\n"); fflush(stdin); op = getchar(); return 0;
 } //fim do carregamento da matriz
 system ("cls");
 printf ("Dados carregados! Pressione [ENTER] para continuar e resolver o sistema linear\n");
 fflush(stdin); op = getchar(); system ("cls");
 //Chama a função que aplica o metodo da eliminação de Gauss e a retrosubstituição
 teste = eliminacao_gauss (n, metodo, a, b, x, o); //retorna zero para teste caso haja sucesso
 if (teste == 1) ///se a função retornar 1, argumentos invalidos foram passados para a função
 {
 printf ("Erro! Argumentos invalidos foram digitados!\n\nPressione [ENTER] para sair\n");
 fflush(stdin); op = getchar(); return 0;
 }
 if (teste == 2) //se a função retornar 2 houve erro de divisão por zero durante o calculo
 {
 printf ("Erro! Ocorreu uma divisao por zero! Talvez nao haja solucao!\n\nPressione [ENTER] para sair\n");
 fflush(stdin); op = getchar(); return 0;
 }
 //exibe o resultado na tela
 printf ("Resultados:\n\n");
 for (i=0; i<n; i++)
 {printf ("x%d = %f\n", o[i], x[i]);}
 printf ("\nDeseja salvar os resultados para um arquivo .csv?\nDigite [S] para sim, ou [N] para nao: ");
 fflush(stdin); op = getchar(); fflush(stdin);
 if (op == 's' || op == 'S') //salva os resultados em um arquivo .csv
 {
 printf ("\nDigite o nome do arquivo onde os resultados serao salvos:\n");
 scanf("%255[^\n]", nome_arq); fflush (stdin);
 strcat (nome_arq, ".csv"); //adiciona a extensao .csv no nome do arquivo
 troca_caractere (nome_arq, ' ', '_'); //substitui ' ' por '_' no nome do arquivo para evitar erros na abertura pela funcao system()
 //cria o arquivo de texto .csv para escrita
 if ((fp = fopen (nome_arq, "w")) == NULL)
 {printf ("\nErro na criacao do arquivo\n\nPressione [ENTER] para sair!\n"); op = getchar(); return 0;}
 //imprime um cabecalho no arquivo de texto .csv - sep=; indica que o separador de colunas eh um ;
 fprintf(fp, "sep=;\n");
 for (i=0; i<(n-1); i++)
 {fprintf (fp, "x%d;", o[i]);}
 fprintf (fp, "x%d\n", o[n-1]);
 //imprime a matriz no arquivo de texto .csv
 for (i=0; i<n; i++)
 {
 for (j=0; j<n; j++)
 {
 snprintf (buffer, 266, "%f", a[i][j]);
 troca_caractere (buffer, '.', ','); //troca o separador
decimal de ponto para virgula, que eh o padrao do Brasil
 fprintf (fp, "%s;", buffer);
 }
 snprintf (buffer, 266, "%f", b[i]);
 troca_caractere (buffer, '.', ','); //troca o separador decimal de ponto para virgula, que eh o padrao do Brasil
 fprintf (fp, "=;%s\n", buffer);
 }
 //imprime os resultados das variaveis
 for (i=0; i<n; i++)
 {
 snprintf (buffer, 266, "x%d =;%f", o[i], x[i]);
 troca_caractere (buffer, '.', ','); //troca o separador decimal de ponto para virgula, que eh o padrao do Brasil
 fprintf (fp, "\n%s", buffer);
 }
 fclose (fp);
 //abre o arquivo com o resultado para o usuario visualizar
 strcpy (buffer, "start ");
 strcat (buffer, nome_arq);
 system (buffer);
 } //fim do procedimento para salvar o resultado em um arquivo .csv
 printf ("\nDeseja reiniciar o programa? (digite [S] para sim, ou [N] para nao): ");
 fflush(stdin); op = getchar(); system ("cls");
 }
 while (op == 's' || op == 'S');
 return 0;
}
Fatoracao LU.c
//Resolucao de sistemas lineares utilizando o metodo da fatoracao LU com pivoteamento parcial
//Luiz Vinicius Soglia - lvmsoglia@hotmail.com
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
//==========================================================================================================
//troca na str o caractere ca pelo caractere cb
void troca_caractere (char *str, const char ca, const char cb)
{
 int n, i;
 n = strlen(str);
 for (i=0; i<n; i++)
 {
 if (str[i] == ca)
 {str[i] = cb;}
 }
}
//==========================================================================================================
//funcao que implementa a resolução de sistemas lineares pela fatoracao LU com pivoteamento parcial
//n: é a ordem do sistema.
//matriz a[][]: 
//é a matriz dos coeficientes. Ao final do metodo ela guardara a matriz LU, com L abaixo da diagonal principal e U nas outras posicoes.
//matriz b[]: é a matriz dos termos independentes.
//matriz x[]: guarda os valores das variaveis após a resolução.
//retorna 0 caso haja sucesso, 1 para erros de entrada de argumentos invalidos, e 2 para erros de divisão por zero.
int fatoracao_LU (int n, float a[][n], float b[], float x[])
{
 
 int k, i, j, posl, erro;
 float m, soma, aux, pivo, y[n];
 
 if (n<2)
 {return 1;} //a ordem do sistema tem que ser maior ou igual a 2
 
 for (i=0; i<n; i++) //inicializa as variaveis x (por precaução)
 {x[i]=0;}
 erro=0; //A variavel erro se tornara 1 caso haja erros de divisao por zero
 //pivoteamento parcial
 for (k=0; k<(n-1); k++)
 {
 pivo=fabs(a[k][k]); //pivo inicial
 posl=k; //posicao da linha do pivo
 for (i=k+1; i<n; i++)
 {
 if (fabs(a[i][k])>pivo)
 {
 pivo=fabs(a[i][k]); //passa a ser o novo pivo
 posl=i; //guarda a posicao da linha do maior pivo
 }
 }
 if (posl!=k) //caso o pivo nao esteja na linha k, troca linha k pela linha posl
 {
 for (j=0; j<n; j++)//permuta as linhas da matriz a[][]
 {
 aux=a[k][j];
 a[k][j]=a[posl][j];
	 a[posl][j]=aux;
 }
 aux=b[k]; //tambem permuta as linhas da matriz b[]
 b[k]=b[posl];
 b[posl]=aux;
 }
 //Triangularizacao da matriz a[][], para a obtenção da matriz LU
	 if (a[k][k] != 0.0) //Evita erros de divisao por zero, caso o pivo seja zero
	 {
 for (i=k+1; i<n; i++)
 {
 m = a[i][k]/a[k][k]; //calcula o multiplicador
 //guarda os multiplicadores nas posicoes que deveriam ser zeradas.
 //Assim a matriz a[][] guarda L abaixo da diagonal principal e guarda U no restante das posicoes. Isso economiza memoria
 a[i][k] = m;
 
 for (j=k+1; j<n; j++) //comeca do elemento apos o valor a ser zerado (que na verdade esta guardando os multiplicadores)
 {
 a[i][j] = a[i][j] - (m*a[k][j]);
 }
 }
 }
 else
 {erro = 1; break;} //Houve erro de divisão por zero
 }
 if (erro == 1) //Houve erro de divisão por zero. Retorna 2, indicando esse erro.
 {return 2;}
 
 //Resolve o sistema L Y = B, obtendo Y
 k=0;
 for (i=0; i<n; i++)
 {
 soma=0.0;
 for (j=0; j<i; j++)
 {
 soma = soma + y[j]*a[i][j]; //a[i][j] neste caso guarda os multiplicadores m (os termos abaixo da diagonal principal da matriz L)
 }
 y[k] = b[i] - soma;
 k++;
 }
 
 //Resolve o sistema U X = Y, obtendo X, utilizando o metodo da resolucao de um sistema triangular superior
 if (a[n-1][n-1] != 0.0)
 {x[n-1] = y[n-1] / a[n-1][n-1];}
 else
 {return 2;} //erro de divisão por zero
 for (i=n-2; i>-1; i--)
 {
 soma = 0.0;
 for (j=i+1; j<n; j++)
 {soma = soma + a[i][j]*x[j];}
 if (a[i][i] != 0)
 {x[i] = (y[i] - soma)/a[i][i];}
 else
 {return 2;} //erro de divisão por zero
 }
 return 0;
}
//==========================================================================================================
//Função principal
int main()
{
 int n, i, j, carregamento, teste;
 char op, nome_arq[260], buffer[64];
 FILE *fp;
 do
 {
 printf ("Resolucao de sistemas lineares utilizando fatoracao LU com pivoteamento parcial\n\n");
 do
 {
 printf ("Digite a ordem do sistema (n), no maximo n=100: ");
 fflush(stdin); scanf ("%d",&n);
 }
 while (n < 2 || n > 100);
 printf ("\nDigite a opcao para o carregamento do sistema linear:\n\n[1] Digitar os dados aqui\n[2] Atraves de um arquivo .txt\n\n");
 do
 {
 printf ("Opcao: ");
 fflush(stdin); scanf ("%d",&carregamento);
 }
 while (carregamento < 1 || carregamento > 2);
 //Cria as matrizes
 float a[n][n], x[n], b[n]; //cria as matrizes dos coeficientes (A), das variaveis (X) e dos termos independentes (B)
 //faz o carregamento da matriz do sistema de acordo com a opcao escolhida
 switch (carregamento)
 {
 case 1: //digita a matriz
 for (i=0; i<n; i++)
 {
 do
 {
 system ("cls");
 printf ("Digite os elementos da linha %d:\n\n", i+1);
 for (j=0; j<n; j++)
 {
 printf ("a[%d][%d] = ", i+1, j+1);
 scanf ("%f", &a[i][j]);
 }
 printf ("\nb[%d] = ", i+1);
 scanf ("%f", &b[i]);
 printf ("\nOs valores digitados estao corretos? (digite [S] para sim, ou [N] para nao): ");
 fflush(stdin); op = getchar();
 }
 while (op != 's' && op != 'S');
 }
 break;
 case 2: //carrega do arquivo
 do
 {
 printf ("\nDigite o caminho do arquivo de texto (com a extensao) que contem os dados:\n");
 fflush(stdin);
 scanf ("%259[^\n]",nome_arq);
 fp=fopen(nome_arq,"r");
 if (!fp)
 {
 printf ("\nErro na abertura do arquivo! Pressione [ENTER] para continuar\n");
 fflush(stdin); op = getchar();
 }
}
 while(!fp);
 //inicializa e lê os coeficientes das matrizes A e B
 for (i=0; i<n; i++)
 {
 for (j=0; j<n; j++)
 {
 a[i][j]=0.0;
 fscanf (fp, "%f", &a[i][j]);
 }
 b[i]=0.0;
 fscanf (fp, "%f", &b[i]);
 }
 fclose(fp);
 break;
 default:
 printf ("\nOcorreu um erro no carregamento do sistema! Pressione [ENTER] para sair\n"); fflush(stdin); op = getchar(); return 0;
 } //fim do carregamento da matriz
 system ("cls");
 printf ("Dados carregados! Pressione [ENTER] para continuar e resolver o sistema linear\n");
 fflush(stdin); op = getchar(); system ("cls");
 //Chama a função que aplica o metodo da fatorcao LU
 teste = fatoracao_LU (n, a, b, x); //retorna zero para teste caso haja sucesso
 if (teste == 1) ///se a função retornar 1, argumentos invalidos foram passados para a função
 {
 printf ("Erro! Argumentos invalidos foram digitados!\n\nPressione [ENTER] para sair\n");
 fflush(stdin); op = getchar(); return 0;
 }
 if (teste == 2) //se a função retornar 2 houve erro de divisão por zero durante o calculo
 {
 printf ("Erro! Ocorreu uma divisao por zero! Talvez nao haja solucao!\n\nPressione [ENTER] para sair\n");
 fflush(stdin); op = getchar(); return 0;
 }
 //exibe o resultado na tela
 printf ("Resultados:\n\n");
 for (i=0; i<n; i++)
 {printf ("x%d = %f\n", i+1, x[i]);}
 printf ("\nDeseja salvar os resultados para um arquivo .csv?\nDigite [S] para sim, ou [N] para nao: ");
 fflush(stdin); op = getchar(); fflush(stdin);
 if (op == 's' || op == 'S') //salva os resultados em um arquivo .csv
 {
 printf ("\nDigite o nome do arquivo onde os resultados serao salvos:\n");
 scanf("%255[^\n]", nome_arq); fflush (stdin);
 strcat (nome_arq, ".csv"); //adiciona a extensao .csv no nome do arquivo
 troca_caractere (nome_arq, ' ', '_'); //substitui ' ' por '_' no nome do arquivo para evitar erros na abertura pela funcao system()
 //cria o arquivo de texto .csv para escrita
 if ((fp = fopen (nome_arq, "w")) == NULL)
 {printf ("\nErro na criacao do arquivo\n\nPressione [ENTER] para sair!\n"); op = getchar(); return 0;}
 //imprime um cabecalho no arquivo de texto .csv - sep=; indica que o separador de colunas eh um ;
 fprintf(fp, "sep=;\nMatriz LU - L abaixo da diagonal principal e U nas outras posicoes\n\n");
 for (i=0; i<(n-1); i++)
 {fprintf (fp, "x%d;", i+1);}
 fprintf (fp, "x%d;;Pb\n", n);
 //imprime a matriz no arquivo de texto .csv
 for (i=0; i<n; i++)
 {
 for (j=0; j<n; j++)
 {
 snprintf (buffer, 266, "%f", a[i][j]);
 troca_caractere (buffer, '.', ','); //troca o separador decimal de ponto para virgula, que eh o padrao do Brasil
 fprintf (fp, "%s;", buffer);
 }
 snprintf (buffer, 266, "%f", b[i]);
 troca_caractere (buffer, '.', ','); //troca o separador decimal de ponto para virgula, que eh o padrao do Brasil
 fprintf (fp, ";%s\n", buffer);
 }
 //imprime os resultados das variaveis
 for (i=0; i<n; i++)
 {
 snprintf (buffer, 266, "x%d =;%f", i+1, x[i]);
 troca_caractere (buffer, '.', ','); //troca o separador decimal de ponto para virgula, que eh o padrao do Brasil
 fprintf (fp, "\n%s", buffer);
 }
 
 fclose (fp);
 //abre o arquivo com o resultado para o usuario visualizar
 strcpy (buffer, "start ");
 strcat (buffer, nome_arq);
 system (buffer);
 } //fim do procedimento para salvar o resultado em um arquivo .csv
 printf ("\nDeseja reiniciar o programa? (digite [S] para sim, ou [N] para nao): ");
 fflush(stdin); op = getchar(); system ("cls");
 }
 while (op == 's' || op == 'S');
 return 0;
}
Jacobi e Gauss Seidel.c
//Resolucao de sistemas lineares utilizando os metodos iterativos de Jacobi e Gauss Seidel
//Luiz Vinicius Soglia - lvmsoglia@hotmail.com
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
//==========================================================================================================
//funcao que implementa a resolução de sistemas lineares pelos metodos iterativos de Jacobi e Gauss Seidel.
//n: é a ordem do sistema.
//metodo: guarda o método a ser utilizado para a resulução: 1 = jacobi, 2 = gauss seidel.
//matriz a[][]: é a matriz dos coeficientes.
//matriz b[]: é a matriz dos termos independentes.
//matriz x[]: guarda os valores das variaveis após a resolução.
//e: é o valor de tolerancia de erro aceitavel no resultado, para ser utilizado como criterio de parada.
//k_max: é o numero de iterações maxima permitida. k_max=0 significa ilimitado (mas na realidade faz 100000 iterações, por segurança).
//O criterio de parada utilizado é o erro relativo: dr = max|xi(k) - xi(k-1)| / max|xi(k)|
//retorna 0 caso haja sucesso, 1 para erros de entrada de argumentos invalidos, 2 para erros de divisão por zero.
int iterativos_jacobi_gauss_seidel (int n, int metodo, float a[][n], float b[], float x[], float e, int k_max)
{
 int k, i, j;
 float s, dr, x_max;
 float x_aux[n]; //variavel auxiliar que guarda os valores das variaveis xi's da iteracao anterior
 
 if (n < 2 || e < 0.0 || k_max < 0) //testa se existe argumentos invalidos
 {return 1;}
 
 if (k_max == 0) //simula um numero de iteracoes "ilimitado" (maximo de 100000 iteracoes)
 {k_max = 100000;}
 switch (metodo) //aplica o metodo iterativo escolhido
 {
 
 //Jacobi ===============================================================
 case 1:
 {
 for (k=1; k<=k_max; k++)
 {
 for (i=0; i<n; i++)
 {x_aux[i] = x[i];} //guarda os valores de x da iteracao anterior
 
 for (i=0; i<n; i++)
 { 
 if (a[i][i] != 0.0) //Evita erros de divisao por zero
	 {
 s = a[i][i]*x_aux[i]; //começa com o termo que nao deveria entrar nas subtrações...para anular sua participação
 for (j=0; j<n; j++)
 {s = s - a[i][j]*x_aux[j];}
 s = b[i] + s;
 x[i] = s / a[i][i];
 }
 else
 {return 2;} //Houve erro de divisão por zero
 }
 
 //tolerancia de erro - busca o valor maximo entre |xi(k) - xi(k-1)|/|xi(k)|, testando se é menor do que erro aceitavel
 dr = fabs(x[0] - x_aux[0]);
 x_max = fabs(x[0]);
 for (i=1; i<n; i++)
 {
 if (fabs(x[i] - x_aux[i]) > dr)
 {dr = fabs(x[i] - x_aux[i]);}
 
 if (fabs(x[i]) > x_max)
 {x_max = fabs(x[i]);}
 }
 dr = dr / x_max;
 if (dr < e) //se dr (erro relativo) for menor do que a tolerancia, a solução é aceitavel e termina a execucao do metodo
 {k++; break;}
 }
 }
 break;
 
 //Gauss Seidel =========================================================
 case 2:
 {
 for (k=1; k<=k_max; k++)
 {
 for (i=0; i<n; i++)
 {x_aux[i] = x[i];} //guarda os valores de x da iteracao anterior
 
 for (i=0;
i<n; i++)
 { 
 if (a[i][i] != 0.0) //Evita erros de divisao por zero
	 {
 s = a[i][i]*x[i]; //começa com o termo que nao deveria entrar nas subtrações...para anular sua participação
 for (j=0; j<n; j++)
 {s = s - a[i][j]*x[j];}
 s = b[i] + s;
 x[i] = s / a[i][i];
 }
 else
 {return 2;} //Houve erro de divisão por zero
 }
 
 //tolerancia de erro - busca o valor maximo entre |xi(k) - xi(k-1)|/|xi(k)|, testando se é menor do que erro aceitavel
 dr = fabs(x[0] - x_aux[0]);
 x_max = fabs(x[0]);
 for (i=1; i<n; i++)
 {
 if (fabs(x[i] - x_aux[i]) > dr)
 {dr = fabs(x[i] - x_aux[i]);}
 
 if (fabs(x[i]) > x_max)
 {x_max = fabs(x[i]);}
 }
 dr = dr / x_max;
 if (dr < e) //se dr (erro relativo) for menor do que a tolerancia, a solução é aceitavel e termina a execucao do metodo
 {k++; break;}
 }
 }
 break;
 //Caso não exista a opção de método passada para a função, implica em erro. Retorna 1, indicando esse erro.
 default:
 return 1;
 } //fim do switch-case com os metodos iterativos
 
 printf ("Foram realizadas %d iteracoes\nErro relativo = max |xi(k) - xi(k-1)| / max |xi(k)| = %f\n\n", k-1, dr);
 return 0;
}
//==========================================================================================================
//funcao que implementa o criterio de convergencia das linhas.
//a[][] é a matriz dos coeficientes.
//retorna o valor de alfa. Se alfa < 1 o método de Jacobi ou Gauss Seidel gera uma sequencia convergente
//retona -1 caso haja elementos iguais a zero na diagonal principal, o que inviabiliza os metodos iterativos de Jacobi e Gauss Seidel
float criterio_linhas (int n, float a[][n])
{
 float alfa, aux;
 int i, j;
 
 alfa=0.0;
 for (i=0; i<n; i++)
 {
 if (a[i][i] != 0.0) //evita divisões por zero
 {
 aux = - fabs(a[i][i]); //inicia alfa com o negativo do termo que nao deve entrar no somatorio, para anular sua participacao
 for (j=0; j<n; j++)
 {
 aux = aux + fabs(a[i][j]);
 }
 aux = aux/fabs(a[i][i]);
 if (aux > alfa)
 {alfa = aux;}
 }
 else
 {return -1;} //Se houver zeros na diagonal principal retorna -1 indicando esse erro
 }
 return alfa; 
}
//==========================================================================================================
//funcao que implementa o criterio de convergencia de Sassenfeld (somente para o metodo de Gauss Seidel).
//a[][] é a matriz dos coeficientes.
//retorna o valor de beta. Se beta < 1 o método de Gauss Seidel gera uma sequencia convergente
//retona -1 caso haja elementos iguais a zero na diagonal principal, o que inviabiliza o metodo iterativo de Gauss Seidel
float criterio_sassenfeld (int n, float a[][n])
{
 float beta[n], beta_max, aux;
 int i, j;
 
 beta_max=0;
 for (i=0; i<n; i++)
 {beta[i] = 1.0;} //inicializa todos os betas com 1, elemento neutro da multiplicacao
 
 for (i=0; i<n; i++)
 {
 if (a[i][i] != 0.0) //evita divisões por zero
 {
 aux = - fabs(a[i][i]); //inicia alfa com o negativo do termo que nao deve entrar no somatorio, para anular sua participacao
 for (j=0; j<n; j++)
 {
 aux = aux + fabs(a[i][j])*beta[j];
 }
 beta[i] = aux/fabs(a[i][i]);
 if (beta[i] > beta_max)
 {beta_max = beta[i];}
 }
 else
 {return -1;} //Se houver zeros na diagonal principal retorna -1 indicando esse erro
 }
 return beta_max; 
}
//==========================================================================================================
//Função principal
int main()
{
 int n, i, j, k_max, metodo, carregamento, teste;
 float e, alfa, beta;
 char op, nome_arq[260];
 FILE *fp;
 do
 {
 printf ("Resolucao de sistemas lineares por metodos iterativos de Jacobi e Gauss Seidel\n\n");
 do
 {
 printf ("Digite a ordem do sistema (n), no maximo n=100: ");
 fflush(stdin); scanf ("%d",&n);
 }
 while (n < 2 || n > 100);
 printf ("\nDigite a opcao do metodo iterativo:\n\n[1] Jacobi\n[2] Gauss Seidel\n\n");
 do
 {
 printf ("Opcao: ");
 fflush(stdin); scanf ("%d",&metodo);
 }
 while (metodo < 1 || metodo > 2);
 
 do
 {
 printf ("\nDigite o numero maximo de iteracoes permitidas (digite 0 para ilimitado): ");
 fflush(stdin); scanf ("%d",&k_max);
 }
 while (k_max < 0);
 
 do
 {
 printf ("\nDigite a tolerancia de erro aceitavel: ");
 fflush(stdin); scanf ("%f",&e);
 }
 while (e < 0.0);
 printf ("\nDigite a opcao para o carregamento do sistema linear:\n\n[1] Digitar os dados aqui\n[2] Atraves de um arquivo .txt\n\n");
 do
 {
 printf ("Opcao: ");
 fflush(stdin); scanf ("%d",&carregamento);
 }
 while (carregamento < 1 || carregamento > 2);
 //Cria as matrizes
 float a[n][n], x[n], b[n]; //cria as matrizes dos coeficientes (A), das variaveis (X) e dos termos independentes (B)
 //faz o carregamento da matriz do sistema de acordo com a opcao escolhida
 switch (carregamento)
 {
 //digita a matriz
 case 1:
 for (i=0; i<n; i++)
 {
 do
 {
 system ("cls");
 printf ("Digite os elementos da linha %d:\n\n", i+1);
 for (j=0; j<n; j++)
 {
 printf ("a[%d][%d] = ", i+1, j+1);
 scanf ("%f", &a[i][j]);
 }
 printf ("\nb[%d] = ", i+1);
 scanf ("%f", &b[i]);
 printf ("\nOs valores digitados estao corretos? (digite [S] para sim, ou [N] para nao): ");
 fflush(stdin); op = getchar();
 }
 while (op != 's' && op != 'S');
 }
 
 do
 {
 system ("cls");
 printf ("Digite a soluca inicial:\n\n");
 for (i=0; i<n; i++)
 {
 printf ("x[%d] = ", i+1);
 scanf ("%f", &x[i]);
 }
 printf ("\nOs valores digitados estao corretos? (digite [S] para sim, ou [N] para nao): ");
 fflush(stdin); op = getchar();
 }
 while (op != 's' && op != 'S');
 break;
 
 //carrega do arquivo
 case 2:
 do
 {
 printf ("\nDigite o caminho do arquivo de texto (com a extensao) que contem os dados:\n");
 fflush(stdin);
 scanf ("%259[^\n]",nome_arq);
 fp=fopen(nome_arq,"r");
 if (!fp)
 {
 printf ("\nErro na abertura do arquivo! Pressione [ENTER] para continuar\n");
 fflush(stdin); op = getchar();
 }
 }
 while(!fp);
 //inicializa e lê os coeficientes das matrizes A e B e a solução inicial
 for (i=0; i<n; i++)
 {
 for (j=0; j<n; j++)
 {
 a[i][j]=0.0;
 fscanf (fp, "%f", &a[i][j]); //matriz A
 }
 b[i]=0.0;
fscanf (fp, "%f", &b[i]); //matriz B
 }
 for (i=0; i<n; i++)
 {fscanf (fp, "%f", &x[i]);} //solucao inicial
 fclose(fp);
 break;
 default:
 printf ("\nOcorreu um erro no carregamento do sistema! Pressione [ENTER] para sair\n"); fflush(stdin); op = getchar(); return 0;
 } //fim do carregamento da matriz
 
 //criterio de convergencia das linhas
 system ("cls");
 printf ("Deseja verificar a convergencia pelo criterio das linhas?\nDigite [S] para sim e [N] para nao: ");
 fflush(stdin); op = getchar();
 if (op == 's' || op == 'S')
 {
 alfa = criterio_linhas (n, a);
 if (alfa >= 0)
 {
 if (alfa < 1)
 {printf ("\nalfa = %f. alfa < 1, convergencia garantida!\n", alfa);}
 else
 {printf ("\nalfa = %f. alfa >= 1, nao existe convergencia garantida!\n", alfa);}
 }
 else
 {
 printf ("\nHa elementos iguais a zero na diagonal principal, isso inviabiliza\nos metodos iterativos!");
 printf (" Tente reagrupar as equacoes para que nao existam zeros\nna diagonal principal!\n\nPressione [ENTER] para sair\n");
 fflush(stdin); op = getchar(); return 0;
 }
 }
 
 //criterio de convergencia de Sassenfeld (somente para o metodo de Gauss Seidel)
 if (metodo == 2) //metodo de Gauss Seidel
 {
 printf ("\nDeseja verificar a convergencia pelo criterio de Sassenfeld?\nDigite [S] para sim e [N] para nao: ");
 fflush(stdin); op = getchar();
 if (op == 's' || op == 'S')
 {
 beta = criterio_sassenfeld (n, a);
 if (beta >= 0)
 {
 if (beta < 1)
 {printf ("\nbeta = %f. beta < 1, convergencia garantida!\n", beta);}
 else
 {printf ("\nbeta = %f. beta >= 1, nao existe convergencia garantida!\n", beta);}
 }
 else
 {
 printf ("\nHa elementos iguais a zero na diagonal principal, isso inviabiliza o metodo\nde Gauss Seidel!");
 printf (" Tente reagrupar as equacoes para que nao existam\nzeros na diagonal principal!\n\nPressione [ENTER] para sair\n");
 fflush(stdin); op = getchar(); return 0;
 }
 }
 }
 printf ("\nDados carregados! Pressione [ENTER] para continuar e resolver o sistema linear\n");
 fflush(stdin); op = getchar(); system ("cls");
 //Chama a função que aplica o metodo iterativo - retorna zero para teste caso haja sucesso
 teste = iterativos_jacobi_gauss_seidel (n, metodo, a, b, x, e, k_max);
 if (teste == 1) //se a função retornar 1, argumentos invalidos foram passados para a função
 {
 printf ("Erro! Argumentos invalidos foram digitados!\n\nPressione [ENTER] para sair\n");
 fflush(stdin); op = getchar(); return 0;
 }
 if (teste == 2) //se a função retornar 2 houve erro de divisão por zero durante o calculo
 {
 printf ("Ocorreu erro de divisao por zero!\n");
 printf ("Tente reagrupar as equacoes para que nao existam zeros na diagonal principal!\n\nPressione [ENTER] para sair\n");
 fflush(stdin); op = getchar(); return 0;
 }
 //exibe o resultado na tela
 printf ("Resultados:\n\n");
 for (i=0; i<n; i++)
 {printf ("x%d = %f\n", i+1, x[i]);}
 printf ("\nDeseja reiniciar o programa? (digite [S] para sim, ou [N] para nao): ");
 fflush(stdin); op = getchar(); system ("cls");
 }
 while (op == 's' || op == 'S');
 return 0;
}

Teste o Premium para desbloquear

Aproveite todos os benefícios por 3 dias sem pagar! 😉
Já tem cadastro?

Continue navegando