Universidade Federal de Minas Gerais Departamento de Ciência da Computação Análise Numérica Trabalho Prático 1 Decomposição LU e Integração Numérica Professor: Frederico Ferreira Campos Filho Alunos: Bruno Xavier da Silva ([email protected]) Diego de Moura Duarte ([email protected]) Belo Horizonte 22 de Abril de 2008 Decomposição LU: O objetivo da primeira parte do trabalho era a implementação, na forma de subprogramas, dos algoritmos de decomposição LU do livro Algoritmos Numéricos 2ªedição. O programa lê um arquivo de nome matriz.dat onde a primeira linha é a ordem N da matriz, as linhas subsequentes devem conter as linhas da matriz de ordem N em seguida as linhas devem conter as linhas do vetor independente que também possui comprimento N. A matriz a ser decomposta deve ter no máximo ordem 100 se for necessário uma decomposição de uma matriz de ordem superior é necessário apenas modificar o formato de leitura do arquivo matriz.dat o que é bastante simples. Conforme pedido na especificação o programa após ler os parâmetros de entrada realiza a decomposição PA=LU, resolve o sistema Ly=Pb, resolve o sistema Ux=y, calcula o determinante da matriz A, acha a norma-2 do vetor resíduo que é dada por r=||b-Ax|| 2 e grava os resultados no arquivo matriz.saida. Utilizando o programa para resolver o sistema que foi passado na especificação, as configurações do arquivo de entrada e a saída gerada para tal sistema são mostradas logo abaixo. Temos primeiro a ordem da matriz, depois a matriz e abaixo deste, o vetor independente. O NC(número de chamada do primeiro aluno da dupla) é igual a quatro. Matriz.dat 5 0. 1. 3. -2. 4. -2. 4. 5. -1. 4. 5. 1. 1. -7. -2. 8. -2. 9. 1. 2. 7. -5. 3. 1. 0. -1. 0.4 2. 0.8 -5. Matriz.saida Decomposicao LU Matriz= 0.0000 -2.0000 5.0000 8.0000 7.0000 1.0000 3.0000 -2.0000 4.0000 4.0000 5.0000 -1.0000 4.0000 1.0000 1.0000 -7.0000 -2.0000 -2.0000 9.0000 1.0000 2.0000 -5.0000 3.0000 1.0000 0.0000 Vetor Independente= -1.0000 0.4000 2.0000 0.8000 -5.0000 Matriz apos decomposicao LU 8.0000 -2.0000 9.0000 1.0000 -0.2500 3.5000 7.2500 -0.7500 0.6250 0.6429 -9.2857 -7.1429 0.0000 0.2857 -0.1000 -2.5000 0.8750 -0.9286 -0.2000 0.8000 Solucao= 13.7141 14.7859 -11.5397 7.5500 8.4833 Determinante= 312.0000 Residuo= 0.000000000000000000000000 0.000000000000001443289932 0.000000000000003552713679 2.0000 4.5000 -6.1429 2.1000 -0.4800 0.000000000000020650148258 0.000000000000018651746814 Norma Segunda= 0.000000000000028089520156 Na impressão dos valores foram utilizados quatro casas decimais exceto para o vetor resíduo e para a norma segunda com o objetivo de mostra que apesar de eles serem muito pequenos ele não são iguais a zero o que seria a conclusão obtida devido ao erro de arredondamento do computador. Código em Fortran da Decomposição LU program main integer i, j, N real*8 Det real*8, dimension(:,:), allocatable :: Matriz real*8, dimension(:), allocatable :: Pivot real*8, dimension(:), allocatable :: Solucao real*8, dimension(:), allocatable :: Vetor_Ind real*8, dimension(:), allocatable :: y real*8, dimension(:), allocatable :: Residuo real*8, dimension(:,:), allocatable :: A real*8 Norma open(25, file='Matriz.dat', status='old') open(10, file='Matriz.saida', status='old') write(10, *) "\t\tDecomposicao LU\n" read(25, *) N allocate(Matriz(N, N)) allocate(Pivot(N)) allocate(Solucao(N)) allocate(Vetor_Ind(N)) allocate(y(N)) allocate(Residuo(N)) allocate(A(N,N)) do i=1, n read(25, *) (Matriz(i,j), j=1, n) enddo do i=1, n read(25, 6) Vetor_Ind(i) enddo close(25, status='keep') do i=1, n do j=1, n A(i,j) = Matriz(i,j) enddo enddo write(10,*) "\nMatriz=" do i=1, n write (10, 6) (Matriz(i,j), j=1, n) enddo write(10,*) "\nVetor Independente=" do i=1, n write (10, 6) Vetor_Ind(i) enddo call Decomposicao_LU(N, Matriz, Det, Pivot) call Subs_Suce_Pivotal(N, Matriz, Vetor_Ind, Pivot, y) call Subs_Retroativas(N, Matriz, y, Solucao) call CalResiduo(N, A, Solucao, Vetor_Ind, Residuo) call Norma2(N, Residuo, Norma) write(10,*) "\nMatriz apos decomposicao LU" do i=1, n write (10, 6) (Matriz(i,j), j=1, n) enddo write(10,*) "\nSolucao=" do i=1, n write (10, 5) Solucao(i) enddo write(10,*) "\nDeterminante=" write(10, 5) Det write(10,*) "\nResiduo=" do i=1, n write (10, 7) Residuo(i) enddo write(10,*) "\nNorma Segunda=" write(10, 7) Norma close(10, status='keep') 5 format(f10.4) 6 format(100f10.4) 7 format(f30.24) end C-----------Decomposição LU-----------C subroutine Decomposicao_LU(N, A, Det, Pivot) real*8 Det, Amax, Mult, t, m, r real*8 A(N, N) real*8 Pivot(N) integer N, i, j, k, p do i=1, n Pivot(i)=i enddo Det=1 do j=1, n-1 p=j Amax=abs(A(j,j)) do k=j+1, n if (abs(A(k,j))>Amax) then Amax=abs(A(k,j)) p=k endif enddo if (p/=j) then do k=1, n t=A(j,k) A(j,k)=A(p,k) A(p,k)=t enddo m=Pivot(j) Pivot(j)=Pivot(p) Pivot(p)=m Det=-Det endif Det=Det*A(j,j) if(abs(A(j,j))/=0) then r=1/A(j,j) do i=j+1, n Mult= A(i,j)*r A(i,j)=Mult do k=j+1, n A(i,k)=A(i,k) - (Mult*A(j,k)) enddo enddo endif enddo Det=Det*A(n,n) end C-----------Substituições Sucessivas Pivotal-----------C subroutine Subs_Suce_Pivotal(ordem, Matriz, Vetor_Ind, Pivot, y) integer ordem real*8 Matriz(ordem,ordem) real*8 Vetor_Ind(ordem) real*8 Pivot(ordem) real*8 y(ordem) real*8 Soma integer k, i, j k= Pivot(1) y(1)=Vetor_Ind(k) do i=2, ordem Soma=0 do j=1, i-1 Soma= Soma + Matriz(i,j) * y(j) enddo k=Pivot(i) y(i)= Vetor_Ind(k) - Soma enddo end C-----------Substituições Retroativas-----------C subroutine Subs_Retroativas(N, U, d, x) integer N, i, j real*8 U(N,N) real*8 d(N) real*8 x(N) real*8 Soma x(N)=d(N)/U(N,N) i = N-1 do while(i>=1) Soma=0 j=i+1 do while(j<=n) Soma = Soma+U(i,j)*x(j) j = j+1 enddo x(i) = (d(i) - Soma)/U(i,i) i = i-1 enddo end C-----------Calcula Resíduo-----------C subroutine CalResiduo(N, Matriz, x, Vetor_Ind, Residuo) integer N real*8 Matriz(N,N) real*8 x(N) real*8 Vetor_Ind(N) real*8 Residuo(N) real*8 Produto(N) call Mult(N, Matriz, x, Produto) call Sub(N, Vetor_Ind, Produto, Residuo) end C-----------Multiplica Matriz por Vetor-----------C subroutine Mult(N, Matriz, vetor, Produto) integer N, i, j real*8 temp real*8 Matriz(N,N) real*8 vetor(N) real*8 Produto(N) do i=1, N temp = 0. do j=1, N temp = temp + Matriz(i,j)*vetor(j) enddo Produto(i) = temp enddo end C-----------Subtrai Vetores-----------C subroutine Sub(N, Vetor1, Vetor2, Subtracao) integer N, i real*8 Vetor1(N) real*8 Vetor2(N) real*8 Subtracao(N) do i=1, N Subtracao(i) = Vetor1(i) - Vetor2(i) enddo end C-----------Calcula Norma-2-----------C subroutine Norma2(N, Vetor, Norma) integer N, i real*8 Vetor(N) real*8 temp real*8 Norma real*8 Somatorio Somatorio = 0. do i=1, N Somatorio = Somatorio + (Vetor(i)*Vetor(i)) enddo Norma = dsqrt(Somatorio) end Integração Numérica: O objetivo da segunda parte do trabalho era a implementação, na forma de subprogramas, dos algoritmos de integração numérica do livro Algoritmos Numéricos 2ªedição. O programa lê um arquivo de nome integral.dat onde a primeira linha é o limite inferior de integração, a segunda é o limite superior de integração, a terceira é a tolerância e a quarta é o número máximo de iterações. A integral a ser calculada deve a ter a sua função de integração escrita no código do programa enquanto os outros parâmetros devem ser modificados no arquivo integral.dat o que é bastante simples. Conforme pedido na especificação, o programa após ler os parâmetros de entrada ele chama a subrotina para integração iterativa, imprime os resultados intermediários, o valor da integral, a menor diferença relativa obtida e a condição de erro e grava os resultados no arquivo integral.saida. Utilizando o programa para resolver a integral que foi passada na especificação, as configurações do arquivo de entrada e a saída gerada para tal integral são mostradas logo abaixo. O NC(número de chamada do primeiro aluno da dupla) é igual a quatro. Integral.dat 1. 4. 1e-8 20. Integral.saida Integracao Limite Inferior = 1.0000 Limite Superior = 4.0000 Tolerancia = 0.000000010000000000000000 Iteracoes = 20.0000 Iter 1 2 3 4 5 n 8 13 21 34 55 Integral 6.42596843753310 6.34109130065408 6.34391038565535 6.34398037927947 6.34398035142837 Dif.Relativa 1.338525702512337E-002 4.443765485161463E-004 1.103307701670910E-005 4.390161363289855E-009 Delta = 4.390161363289855E-009 Integral = 6.34398035142837 CondErro = 0 Código em Fortran da Integração Numérica program main integer n integer CondErro real*8 a, b, Integral, Toler, IterMax, Delta open(100, file='integral.dat', status='old') read(100, *) a read(100, *) b read(100, *) Toler read(100, *) IterMax close(100, status='keep') open(200, file='integral.saida', status='old') write(200,*) "\t\tIntegracao\n" write(200,'(a, f10.4)')"Limite Inferior =\n",a write(200,'(a, f10.4)')"\nLimite Superior =\n",b write(200,'(a, f33.24)')"\nTolerancia =\n",Toler write(200,'(a, f10.4)')"\nIteracoes =\n",IterMax call GL_Iter(a,b,Toler,IterMax,Integral,Delta,CondErro) close(200, status='keep') 5 format(f10.4) end C-----------Gauss-Legendre-Iterativo-----------C subroutine GL_Iter(a,b,Toler,IterMax,Integral,Delta,CondErro) integer CondErro real*8 a, b, Toler, IterMax real*8 Integral,Delta,Int2 integer Iter, n1, n2 Iter = 1 n1 = 5 n2 = 8 call Gauss_Legendre(a,b,n2,Int2,CondErro) write(200, *) "\n\tIter\t n\tIntegral\t\tDif.Relativa" write(200, *) Iter, n2, Int2 c Repita 10 Iter = Iter+1 n = n1 + n2 call Gauss_Legendre(a,b,n,Integral,CondErro) if(Integral /= 0) then Delta = abs((Integral-Int2)/Integral) else Delta = abs(Integral-Int2) endif write(200, *) Iter, n, Integral, Delta if(Delta <= Toler .or. Iter == IterMax) then goto 20 endif Int2 = Integral n1 = n2 n2 = n goto 10 20 write(200,*) "\nDelta =" write(200, *) Delta write(200,*) "\nIntegral =" write(200, *) Integral write(200,*) "\nCondErro =" write(200, *) CondErro if(Delta<=Toler)then CondErro = 0 else CondErro = 1 endif end C-----------PesAbsGL-----------C subroutine PesAbsGL(n, A, T, CondErro) integer n, m, i, j integer CondErro real*8 A(n) real*8 T(n) real*8 pi real*8 z, z1 real*8 p1, p2, p3, p4, pp if( n < 1 ) then CondErro = 1 return endif CondErro = 0 pi = 3.14159265358979323846 m = aint(0.5 * (n+1)) do i=1, m z=cos(pi*(i-0.25)/(n+0.5)) c REPITA 30 p1 = 1 p2 = 0 do j=1, n p3 = p2 p2 = p1 p1 = ((2*j-1)*z*p2-(j-1)*p3)/j enddo pp = n*(z*p1 - p2)/(z*z - 1) z1 = z z = z1-p1/pp if(abs(z-z1) >= 1e-15)then goto 30 endif T(m + 1 - i) = z A(m + 1 - i) = 2/((1-z*z)*pp*pp) enddo end C-----------Gauss-Legendre-----------C subroutine Gauss_Legendre(a, b, n, Integral, CondErro) integer CondErro, n, i, k real*8 a, b, c, Integral, e1, e2, c1, c2, t, x real*8, dimension(:), allocatable :: Avet real*8, dimension(:), allocatable :: Tvet real*8 temp allocate(Avet(n)) allocate(Tvet(n)) Integral=0. call PesAbsGL(n, Avet, Tvet, CondErro) if (CondErro/=0) then return endif e1=(b-a)/2 e2=(a+b)/2 if (mod(n,2)==0) then c1=1 c2=0.5 else c1=0 c2=1 endif do i=1, n k=dint(i-0.5 * (n+1)+ Sinal(i-0.5 * (n+c1)) * c2) temp = k t=Sinal(temp)*Tvet(abs(k)) x= e1*t + e2 y=F(x) c=Avet(abs(k)) Integral= Integral + y*c enddo Integral=e1*Integral end C-----------Sinal-----------C function Sinal(Valor) real*8 Valor if(Valor>0.) then Sinal=1 endif if(Valor<0.) then Sinal=-1 endif if(Valor == 0) then Sinal=0 endif end C-----------F(x) (Função a ser integrada)-----------C function F(x) real*8 x, temp, NC NC=4. temp=sin(5*x)*sin(5*x) temp= NC + temp F=dsqrt(temp) end