




                                CAPTULO 8          
            
                            VETORES E MATRIZES   
            
            
            8.1. VETORES       
            
                 Um vetor   um conjunto formado por uma quantidade fixa  
            de dados  de um  mesmo tipo.  Sua declarao   feita  com a
            palavra reservada  ARRAY, seguida de seus limites inferior e
            superior entre  colchetes e  separados entre si por "..", da
            palavra reservada  OF e  o tipo de cada componente do vetor.
            Os limites inferior e superior devem ser do tipo ordinal.
            
                 TYPE
                   Vetor = ARRAY[LimInf..LimSup] of TipoBase;
            
                 Um  vetor   tambm  costuma  ser  chamado  de  varivel    
            indexada ou varivel composta homognea.         
                 Para se  ter acesso  n-sima componente de um vetor V,
            deve-se fazer  referncia a  V[n]. A  definio de  um vetor
            pode ser  feita  atribuindo-se  valores  a  cada  componente
            individualmente  ou   lendo-se   cada   componente   de   um
            dispositivo de  entrada. Nestes  casos   comum o  uso de um
            FOR:
                           FOR n := LimInf TO LimSup DO
                             V[n] := valor;
            ou
                           FOR n := LimInf TO LimSup DO
                             Readln(V[n]);
            
                 Em um  bloco de  declaraes CONST,  um vetor  pode ser
            definido listando-se todas suas componentes entre parnteses
            e separadas entre si por vrgulas:
            
                           CONST
                             V: vetor = (a_1, a_2, ..., a_n);
            
            Exemplo:  As   declaraes  a   seguir  definem  os  vetores
            i =  (1, 0,  0), j  = (0,  1, 0)  e k  = (0,  0, 1),  a base
            cannica do R^3.
            
                           TYPE
                             VetorDoR3 = ARRAY[1..3] OF real;
            
                           VAR
                             i, j, k: VetorDoR3;
            
                             ...
                             i[1] := 1; i[2] := 0; i[3] := 0;
                             j[1] := 0; j[2] := 1; j[3] := 0;
                             k[1] := 0; k[2] := 0; k[3] := 1;
            
                 Outra opo para se definir i, j, k:

                                       - 105 -





            
                           CONST
                             i: VetorDoR3 = (1, 0, 0);
                             j: VetorDoR3 = (0, 1, 0);
                             k: VetorDoR3 = (0, 0, 1);
            
                 No bloco  de declaraes  CONST, i,  j e  k  devem  vir
            acompanhados dos respectivos tipos (VETORDOR3).
            
            Exemplo:  Definir um vetor V do R^10, cuja n-sima componente
            seja igual ao quadrado de n.
            
                 TYPE
                   Vetor10 = ARRAY [1..10] OF real;
            
                 VAR
                   V: Vetor10;
                   n: byte;
            
                   ...
                   for n := 1 to 10 do
                     V[n] := Sqr(n);
            
            Outra alternativa para a definio de V:
            
                 CONST
                   V: Vetor10 = (1, 4, 9, 16, 25, 36, 49, 64, 81, 100);
            
            Exemplo: As  componentes de  um vetor  podem ser de qualquer
            tipo. No  bloco de declaraes CONST abaixo, esto definidos
            um vetor  X de caracteres, um vetor Y de strings, um vetor Z
            booleano e um vetor M de vetores.
            
              TYPE
                VetCaracteres = ARRAY [1..5] OF char;
                VetStrings    = ARRAY [1..3] OF string[20];
                VetBooleano   = ARRAY [1..4] OF boolean;
                VetInteiro    = ARRAY [1..2] OF integer;
                VetorDeVetor  = ARRAY [1..4] OF VetInteiro;
            
              CONST
                X: VetCaracteres = ('a', 'b', 'c', 'd', 'e');
                Y: VetStrings    = ('Andrade', 'Rodrigues', 'Freitas');
                Z: VetBooleano   = (TRUE, FALSE, FALSE, TRUE);
                M: VetorDeVetor  = ( (1, 2), (0, 3), (-3, 5), (0, -1) );
            
                 Com as definies acima, temos que:
            
                 X[2] =  'b', X[5]  = 'e',  Y[2] =  'Rodrigues', Z[1]  =
            TRUE, Z[2]  = FALSE, M[3] = (-3, 5), M[3][1] = -3, M[3][2] =
            5  e  M[4][1] = 0.
            
            Exemplo:  O   intervalo  LimInf..LimSup  especificado  entre
            colchetes,   direita da  palavra  ARRAY,  no  precisa  ser

                                       - 106 -





            necessariamente um  subconjunto de  inteiros positivos. Pode
            ser qualquer  intervalo de  tipos ordinais.  Neste  exemplo,
            definimos um  tipo enumerado DIAS para servir de ndice para
            um  vetor   TRAB,  que  guarda  informaes  a  respeito  da
            quantidade de horas trabalhadas ao longo de uma semana.
            
            PROGRAM HorasTrabalhadas;
            
            TYPE
              Dia = (dom, seg, ter, qua, qui, sex, sab);
              Info = ARRAY [dom..sab] OF byte;
            
            CONST
              NomeDoDia: ARRAY [dom..sab] OF string =
                         ('domingo',     'segunda-feira', 'terca-feira',
                          'quarta-feira', 'quinta-feira', 'sexta-feira',
                          'sabado');
            
            VAR
              i: Dia;
              Trab: Info;
              soma: integer;
            
            BEGIN
              (* Entrada dos dados *)
              for i := dom to sab do
              begin
                Write('Quantidade de horas trabalhadas ', NomeDoDia[i],
                                                                 ' : ');
                Readln(Trab[i]);
              end;
            
              (* Calculo do total *)
              soma := 0;
              for i := dom to sab do
                soma := soma + Trab[i];
            
              Writeln;
              Writeln('Total de horas trabalhadas = ', soma)
            END.
            
            Exemplo: A  nica desvantagem  dos vetores  do Pascal,  que
            seu tamanho  (dimenso) precisa ser fixado na sua declarao
            e o programa NO pode alterar esse tamanho. Para um programa
            manusear vetores  de diferentes tamanhos, um truque bastante
            comum   se declarar o tipo vetor usando o maior tamanho que
            ser necessrio.  Desse modo o programa poder trabalhar com
            vetores  de   tamanhos  menores  do  que  o  tamanho  mximo
            declarado,   bastando    para   isso   desperdiar   algumas
            coordenadas, o  que corresponde  a  desperdiar  memria  do
            computador.
                 Neste exemplo,  definiremos uma funo VMAX que calcula
            o maior  elemento de um vetor real de tamanho no mximo 100.
            A funo  VMax deve  ter dois  parmetros: o  vetor V  e seu

                                       - 107 -





            respectivo tamanho  n. Se  o leitor ficou pensando que amos
            dizer que  a definio de uma funo VMIN seria anloga, ele
            acertou.
            
            TYPE
              Vetor = ARRAY [1..100] OF real;
            
            FUNCTION VMax(V: Vetor; n: byte): real;
            
            (* Determina o maior dos n primeiros elementos do vetor V *)
            
            VAR
              i: byte;
              maximo: real;
            
            BEGIN
              maximo := V[1]; (* Chutamos inicialmente que o maior *)
                              (* elemento de V  o primeiro.       *)
            
              (* Comparamos, MAXIMO com todos os elementos V[i] de V. *)
              (* Sempre que MAXIMO < V[i], redefinimos MAXIMO := V[i] *)
              for i := 1 to n do
                if maximo < V[i] then maximo := V[i];
              VMax := maximo
            END;
            
                 Neste exemplo, o vetor V s fica bem definido fornecen-
            do-se os  valores de  V e de n. H uma maneira natural de se
            superar esse  problema de se ter 2 informaes independentes
            ("V" e  "n") para  um  mesmo  dado:  basta  usar  registros.
            Definiremos um  tipo REG_VETOR, cujos campos so o tamanho e
            o vetor (declarado como ARRAY). Temos assim uma boa opo de
            se definir um vetor de tamanho varivel. Vamos definir agora
            uma funo  NMAX, semelhante   VMAX  anterior  s  que  ela
            retorna a  posio N  do maior  elemento do vetor, e no seu
            valor.
            
            CONST
              TamMax = 100; (* Tamanho maximo dos vetores *)
            
            TYPE
              Reg_Vetor = record
                tam: byte;
                vetor: ARRAY [1..TamMax] OF real;
              end;
            
            FUNCTION NMax(V: Reg_Vetor): byte;
            
            (* Determina  a posicao  do maior  elemento do vetor V, cujo
            tamanho   dado  por  V.TAM  e  cujo  i-esimo  elemento  
            V.VETOR[i] *)
            
            VAR
              m, i: byte;

                                       - 108 -





              ValorMaximo: real;
            
            BEGIN
              (* Inicialmente, supomos que o maior elemento de V  o
                 primeiro *)
              m := 1; ValorMaximo := V.vetor[m];
            
              (* A seguir, comparamos ValorMaximo com  todos os outros
                 elementos de V, redefinindo  ValorMaximo  sempre  que
                 for necessario *)
              for i := 1 to V.tam do
                if (ValorMaximo < V.vetor[i]) then
                begin
                  m := i;
                  ValorMaximo := V.vetor[m]
                end;
              NMax := m
            END;
            
                 Se X  for uma varivel do tipo REG_VETOR, ento NMax(X)
             a  posio do  maior elemento  de X,  alis, de X.VETOR. O
            valor mximo  assumido pelas  componentes de  X.VETOR  dado
            por X.VETOR[NMax(X)].
            
            Exemplo: Um  polinmio   p(x) =  a_n x^n + ... + a_1 x + a_0
            pode ser pensado como se fosse um vetor:
                              p = (a_0, ..., a_n-1, a_n).
                 Neste exemplo,  definiremos um  polinmio como sendo um
            registro, cujos  campos so  o grau  e  os  coeficientes  do
            polinmio. Suporemos que o grau mximo seja 30.
            
                           CONST
                             GrauMax = 30;
            
                           TYPE
                             polinomio = record
                               grau: byte;
                               coef: ARRAY [0..GrauMax] of real;
                             end;
            
                 Por exemplo,  o polinmio  p(x) =  x^2 - 5x + 6 pode ser
            definido da seguinte forma:
            
                      VAR p: polinomio;
                      ...
                      p.grau := 2;
                      p.coef[2] := 1; p.coef[1] := -5; p.coef[0] := 6;
            
                 Neste  exemplo,   so   despediadas   as   outras   27
            coordenadas do  vetor P.COEF.  No existe maneira simples de
            se superar esse problema.
            

                                       - 109 -





                 Na diviso de um polinmio p(x) = a_n x^n + ... + a_1x + a0
            por g(x)  = x  - b,  obtemos um quociente q(x) de grau n - 1
            cujos coeficientes so dados por
            
                           q_n-1 := a_n
                           q_n-2 := b*q_n-1 + a_n-1
                           ...
                           q_i := b*q_i+1 + a_i+1
                           ...
                           q_0 := b*q_1 + a_1
                           Resto da diviso = b*q0 + a0 = p(b)
            
                 O algoritmo  acima   conhecido  pelo  nome  de  Briot-
            Ruffini.
            
                 Vamos agora,  definir  um  procedimento  DIVIDEPOL  que
            fornece o  quociente q(x)  e o  resto r  da  diviso  de  um
            polinmio a(x) por x - b.
            
            PROCEDURE DividePol(a: polinomio; b: real; VAR q: polinomio;
                                                       VAR r: real);
            
            (*               a(x) = q(x)*(x - b) + r                  *)
            
            VAR
              i, n: byte;
            
            BEGIN
              n := a.grau;
              q.grau := n - 1;
            
              q.coef[n - 1] := a.coef[n];
              for i := n - 2 downto 0 do
                q.coef[i] := b*q.coef[i + 1] + a.coef[i + 1];
              r := b*q.coef[0] + a.coef[0];
            END;
            
                 Para ler um polinomio, temos o seguinte procedimento:
            
            PROCEDURE LePolinomio(VAR p: polinomio);
            
            (* Le o grau e coeficientes do polinomio p *)
            
            VAR
              i: byte;
            
            BEGIN
              Write('Grau de p(x)? '); Readln(p.grau);
              Writeln;
              for i := p.grau downto 0 do
              begin
                Write('Coeficiente do termo de grau ', i, ' = ');
                Readln(p.coef[i]);
              end;

                                       - 110 -





            END;
            
                 Para mostrar um polinmio na tela, temos o procedimento
            MostraPolinomio seguinte:
            
            PROCEDURE MostraPolinomio(q: polinomio);
            
            (* Mostra na tela o polinomio q *)
            
            VAR
              i: byte;
            
            BEGIN
              Write('Grau de q(x) = '); Writeln(q.grau);
              Writeln;
              Writeln('Coeficientes de q(x) (ordem decrescente das ',
                                                       'potncias) : ');
              Writeln;
              for i := q.grau downto 0 do
                Write(q.coef[i]:8:3);
              Writeln;
            END;
            
                 Supondo  que   os  procedimentos   e  tipo  "polinomio"
            anteriores estejam  gravados em disco sob o nome de POLI.INC
            ("INC" de  "incluso"). Temos o seguinte programa-exemplo de
            uso de DividePol.
            
            PROGRAM DividindoPolinomios;
            
            {$I POLI.INC}
            
            VAR
              p, q: polinomio;
              a, r: real;
            
            BEGIN
              Writeln;
              Writeln('*** DIVISAO DE UM POLINOMIO p(x) POR x - a ***');
              Writeln;
              Write('Valor de a? '); Readln(a);
              Writeln;
              LePolinomio(p);
              Writeln;
              DividePol(p, a, q, r);
              Writeln('QUOCIENTE DA DIVISAO = q(x)');
              Writeln;
              MostraPolinomio(q);
              Writeln;
              Writeln('RESTO DA DIVISAO = ', r:8:3);
            END.
            

                                       - 111 -





                 Como exemplo  de  execuo  desse  programa,  temos  as
            seguintes mensagens,  que mostram  o resultado da diviso de
            p(x) = xS03T + 1  por  x + 1 :
            
            *** DIVISAO DE UM POLINOMIO p(x) POR x - a ***
            
            Valor de a? -1
            
            Grau de p(x)? 3
            
            Coeficiente do termo de grau 3 = 1
            Coeficiente do termo de grau 2 = 0
            Coeficiente do termo de grau 1 = 0
            Coeficiente do termo de grau 0 = 1
            
            QUOCIENTE DA DIVISAO = q(x)
            
            Grau de q(x) = 2
            
            Coeficientes de q(x) (ordem decrescente das potncias) :
            
               1.000  -1.000   1.000
            
            RESTO DA DIVISAO =    0.000
            
            Exemplo: A  funo Valor(p,  a) a  seguir, fornece  o  valor
            numrico do polinomio p(x) no ponto em que x = a.
            
            FUNCTION Valor(p: polinomio; a: real): real;
            
            VAR
              p_aux: polinomio;
              r: real;
            
            BEGIN
              DividePol(p, a, p_aux, r);     (* p(a) = resto da divi- *)
              Valor := r                     (* sao de p(x) por x - a *)
            END;
            
                 Para a  execuo do  prximo programa, essa funo deve
            ser includa no arquivo de incluso POLI.INC anterior.
            
            Exemplo: Neste  exemplo, vamos  elaborar um procedimento que
            nos d  todas as  razes racionais  de um  polinmio p(x) de
            coeficientes inteiros.  Vamos usar as informaes do arquivo
            POLI.INC anterior.
            
            
            PROGRAM RaizesRacionais;
            
            {$I POLI.INC}
            
            (* ------------------------------------------------------ *)
            

                                       - 112 -





            PROCEDURE CalculaUmaRaizRacional(VAR f: polinomio;
                               VAR TemRaiz: boolean; VAR RaizRac: real);
            
            (* Verifica se o polinomio f(x) tem alguma raiz racional. Se
            tiver, a variavel TEMRAIZ ser TRUE. A raiz ser informada
            ao programa principal atraves da variavel RAIZRAC         *)
            
            CONST
              MaxDivisores = 1000;
              epsilon = 1E-8;
            
            TYPE
              divisores = record    (* DIVISORES guarda informaes a *)
                quant: word;        (* respeito dos divisores positi- *)
                vetor: ARRAY[1..MaxDivisores] of word;
              end;                  (* vos de f.coef0 e f.coefn.      *)
            
            VAR
              p, q: divisores;
              aux: real;
              i, j, CoefAux: word;
            
            BEGIN
              (* Caso particular em que o grau de f(x)  1 *)
              if (f.grau = 1) then
              begin
                TemRaiz := true;
                RaizRac := -f.coef[0]/f.coef[1];
                f.grau := 0;  (* Esta atribuicao servira' para avisar *)
                Exit;         (* ao programa principal para encerrar. *)
              end;
            
              (* Calculo dos  divisores positivos  do  termo  constante.
                 p.quant  e' a quantidade de divisores e  p.vetor[i]  e'
                 o  i-esimo divisor encontrado.  Em qualquer caso, temos
                 pelo menos dois divisores: 1 e f.coef[0]             *)
            
              CoefAux := Abs(Trunc(f.coef[0]));  (* A funcao TRUNC e' *)
              (* necessaria pois f.coef[0]  real e CoefAux  inteiro *)
            
              p.quant := 2;
              p.vetor[1] := 1;
              p.vetor[2] := CoefAux;
              for i := 2 to (CoefAux DIV 2) do
                if (CoefAux MOD i = 0) then
                begin
                  Inc(p.quant); (* O mesmo que p.quant := p.quant + 1 *)
                  p.vetor[p.quant] := i
                end;
            
              (* Calculo dos divisores positivos do coeficiente do termo
                 de maior grau do polinomio.  q.quant e' a quantidade de
                 divisores e  q.vetor[i]  e' o i-esimo divisor encontra-
                 do. Em qualquer caso, temos pelo menos  dois  divisores

                                       - 113 -





                 1 e f.coef[f.grau].                                  *)
            
              CoefAux := Abs(Trunc(f.coef[f.grau]));
              q.quant := 2;
              q.vetor[1] := 1;
              q.vetor[2] := CoefAux;
              for i := 2 to (CoefAux DIV 2) do
                if (CoefAux MOD i = 0) then
                begin
                  Inc(q.quant);             (* q.quant := q.quant + 1 *)
                  q.vetor[q.quant] := i
                end;
            
              TemRaiz := false;
              for i := 1 to p.quant do
                for j := 1 to q.quant do
                begin
            
                  (* Calculo de uma raiz racional positiva *)
                  aux := p.vetor[i]/q.vetor[j];
                  if (Abs(Valor(f, aux)) < epsilon) then   (* Este IF *)
                  begin                 (* seria     equivalente    a *)
                    TemRaiz := true;    (* IF (Valor(f, aux) = 0) ... *)
                    RaizRac := aux;     (* se no houvesse  problemas *)
                    Exit;               (* de aproximao.            *)
                  end;
            
                  (* Calculo de uma raiz racional negativa *)
                  aux := -p.vetor[i]/q.vetor[j];
                  if (Abs(Valor(f, aux)) < epsilon) then
                  begin
                    TemRaiz := true;
                    RaizRac := aux;
                    Exit;
                  end;
            
                end; (* fim do FOR j... *)
            END; (* fim do procedimento CalculaUmaRaizRacional *)
            
            (* ------------------------------------------------------ *)
            
            TYPE
              solucao = record  (* o registro SOLUCAO guarda informa- *)
                quant: byte;    (* es a respeito das razes  racio- *)
                raiz: ARRAY [1..GrauMax] of real;             (* nais *)
              end;
            
            VAR
              p, p_aux: polinomio;
              x: solucao;
              i: byte;
              ra resto: real;
              TemRaizRacional: boolean;
            

                                       - 114 -





            BEGIN (* inicio do programa principal *)
              Writeln;
              Writeln('CALCULO DAS RAIZES RACIONAIS DE p(x) = 0');
              Writeln;
              LePolinomio(p);
              Writeln;
            
              (* CALCULO DAS RAIZES RACIONAIS
            
                      Sao feitas sucessivas chamadas ao  procedimento
                 CalculaUmaRaizRacional. Aps cada chamada, o grau do
                 polinmio fica menor se ele tiver alguma raiz racio-
                 nal. As chamadas a CalculaUmaRaizRacional devem ter-
                 minar quando o grau do polinmio for menor do que  1
                 ou o polinmio no tiver raiz racional.              *)
            
              x.quant := 0; (* Quantidade de raizes conhecidas *)
              repeat
                CalculaUmaRaizRacional(p, TemRaizRacional, rac);
                if TemRaizRacional then
                begin
                  Inc(x.quant);  (* Incrementa x.quant de uma unidade *)
                  x.raiz[x.quant] := rac;
                  if (p.grau >= 2) then
                  begin
                    DividePol(p, ra p_aux, resto);
                    p := p_aux;
                  end;
                end;
              until (p.grau < 1) or (not TemRaizRacional);
            
              (* Impressao dos resultados *)
              if (x.quant = 0) then
                Writeln('A equacao nao tem raizes racionais.')
              else
              begin
                Writeln('Raizes racionais:');
                Writeln;
                for i := 1 to x.quant do
                  Write(x.raiz[i]:10:6);
                Writeln;
              end;
            END. (* fim do programa *)
            
               Um exemplo de execuo, resolvendo-se 3x^3+x^2-12x-4 = 0:
            
            CALCULO DAS RAIZES RACIONAIS DE p(x) = 0
            
            Grau de p(x)? 3
            
            Coeficiente do termo de grau 3 = 3
            Coeficiente do termo de grau 2 = 1
            Coeficiente do termo de grau 1 = -12
            Coeficiente do termo de grau 0 = -4

                                       - 115 -





            
            Raizes racionais:
            
             -0.333333  2.000000 -2.000000
            
            
            8.2. MATRIZES    
            
                 Uma matriz  pode  ser  considerada  como  um  vetor  de
            vetores:
            
                 TYPE
                   vetor = ARRAY [1..3] OF real;
                   matriz = ARRAY [1..3] OF vetor;    (* matriz 3 x 3 *)
            
                 No entanto,   possvel  se declarar  os  intervalo  de
            variao dos  ndices de  uma s  vez, bastando para isso se
            separar cada intervalo do outro por uma vrgula:
            
                 TYPE
                   matriz3x3 = ARRAY [1..3, 1..3] of real;
                   matriz2x5 = ARRAY [1..2, 1..5] of real;
                   matriz4x6 = ARRAY [1..4, 1..6] of integer;
            
                 O elemento (i, j) de uma matriz M pode ser referenciado
            como M[i, j] ou como M[i][j].
            
            Exemplo: Para  se definir  os elementos  de uma  matriz, so
            necessrias leituras  ou  atribuies  para  cada  elemento.
            Normalmente, essas  atribuies so  feitas com  2 laos FOR
            encaixados, um FOR para cada ndice:
            
                 FOR i := 1 TO m DO     ou    FOR i := 1 TO m do
                   FOR j := 1 TO n DO           FOR j := 1 TO n do
                     a[i, j] := valor;            Readln(a[i, j]);
            
                 Em um  bloco de  declaraes CONST, uma matriz pode ser
            definida na forma:
            
                      CONST
                        matriz: tipo = ((a_11, ..., a_1n),
                                         ...,
                                        (a_m1, ..., a_mn));
            
                 Se a  matriz  for  pequena,  o  usurio  pode  preferir
            definir a matriz elemento por elemento (sem usar laos FOR).
            Abaixo esto definidas 2 matrizes M e N  2 x 2, ambas iguais
             matriz identidade:
            
                 TYPE
                   matriz2x2 = ARRAY [1..2, 1..2] OF integer;
            
                 VAR
                   M: matriz2x2;

                                       - 116 -





            
                 CONST
                   N: matriz2x2 = ((1, 0), (0, 1));
            
                   ...
                   M[1, 1] := 1; M[1, 2] := 0;
                   M[2, 1] := 0; M[2, 2] := 1;
            
            Exemplo: Neste  exemplo, definimos  uma matriz  A 5 x 6 cujo
            elemento a_ij  dado por
                                 a_ij = 2i^3 - j^2 + 1
                                          
            TYPE
              matriz5x6 = ARRAY [1..5, 1..6] OF integer;
            
            VAR
              i, j: byte;
              A: matriz5x6;
            
            BEGIN
              for i := 1 to 5 do
                for j := 1 to 6 do
                  A[i, j] := 2*i*i*i - j*j + 1;
            END.
            
                 Para se  trabalhar com  matrizes de  diversos tamanhos,
            devemos  declarar   as  matrizes   usando  o  maior  tamanho
            possvel. Nestes  casos,   conveniente  se  pensar  em  uma
            matriz  como   sendo  um   registro  cujos   campos  so  as
            quantidades de  linhas e  colunas e  os elementos da matriz.
            Suporemos que  o tamanho  mximo das  matrizes   10  x  10.
            Usaremos as declaraes a seguir at o final deste captulo.
            
            CONST
              MaxM = 10;
              MaxN = 10;
            
            TYPE
              matriz = record
                m, n: byte;
                a: ARRAY [1..MaxM, 1..MaxN] OF real;
              end;
            
                 Por exemplo, a matriz X = | -2  4 |  pode ser declarada
                                           |  5  0 |
            da seguinte forma:
            
                 VAR
                   X: matriz;
                   ...
                   X.m := 2;    (* Quantidade de linhas  de X *)
                   X.n := 2;    (* Quantidade de colunas de X *)
                   X.a[1, 1] := -2; X.a[1, 2] := 4;
                   X.a[2, 1] :=  5; X.a[2, 2] := 0;

                                       - 117 -





            
            Exemplo: Neste exemplo, construmos um procedimento que faa
            a leitura  pelo teclado  de uma  matriz  X.  Internamente  a
            matriz ser  X, mas na tela ela pode aparecer com outro nome
            (A, B,  ...). Para  isso, usaremos o parmetro auxiliar NOME
            do tipo  char. Usaremos tambm uma "chave" chamada OPCAO que
            decidir se  o procedimento  deve solicitar  do  usurio  as
            dimenses da matriz (caso em que OPCAO <> 0), ou se isso no
             necessrio  (no caso do programa principal j ter decidido
            a ordem da matriz, que convencionaremos com OPCAO = 0).
            
            PROCEDURE LeMatriz(VAR X: matriz; opcao: byte; nome: char);
            
            VAR
              i, j: byte;
            
            BEGIN
              Writeln;
              if (opcao <> 0) then
              begin
                Write('Quantidade de linhas da matriz ', nome, '? ');
                Readln(X.m);
                Write('Quantidade de colunas da matriz ', nome, '? ');
                Readln(X.n);
                Writeln;
              end;
              Writeln('Fornea os elementos da matriz ', nome);
              Writeln;
              for i := 1 to X.m do    (* Para cada linha i, usamos um *)
              begin           (* FOR j... para ler todos os elementos *)
                Write('Linha ', i, ': ');                 (* da linha *)
                for j := 1 to X.n do Read(X.a[i, j]);
              end;
            END;
            
            Exemplo:   Neste    exemplo,   uma   matriz   X      gerada
            aleatoriamente. Para  isso usamos  os comandos  RANDOMIZE  e
            RANDOM para gerar elementos inteiros positivos.
            
            PROCEDURE MatrizAleatoria(VAR X: matriz);
            
            VAR
              i, j: byte;
            
            BEGIN
              Randomize;
              X.m := Random(10) + 1; (* Inteiro no intervalo [1, 10] *)
              X.n := Random(10) + 1;
              for i := 1 to X.m do
                for j := 1 to X.n do
                  X.a[i, j] := Random(100);
            END;
            

                                       - 118 -





                 Deixaremos, como  exerccio, que  o usurio  acrescente
            (com mais um RANDOM) um sinal aleatrio aos elementos de X.
            
            Exemplo: Neste  exemplo,  construmos  um  procedimento  que
            mostra uma matriz X na tela:
            
            PROCEDURE MostraMatriz(X: matriz);
            
            VAR
              i, j: byte;
            
            BEGIN
              Writeln;
              for i := 1 to X.m do
              begin
                for j := 1 to X.n do
                  Write(X.a[i, j]:8:3);
                (* Quando o FOR j ... tiver  sua execuo completada,
                   ento  chegado o final de uma  linha e,  devido a
                   isso, devemos mudar para uma nova linha:           *)
                Writeln;
              end; (* fim do  FOR i...  *)
              Writeln;
            END; (* fim do procedimento MostraMatriz *)
            
            Exemplo: Aps  esses procedimentos  iniciais  de  entrada  e
            sada  de  matrizes,  vamos  elaborar  alguns  que  permitam
            algumas operaes  com matrizes.  No podemos  usar  funes
            para realizar essas operaes, pois o tipo de retorno de uma
            funo no admite registros e nem o tipo ARRAY. A idia ser
            sempre enviar  uma ou  mais matrizes  para  um  procedimento
            atravs de  uma passagem  de  parmetro  por  valor  (sem  a
            palavra VAR)  e esperar  o resultado  em um  outro parmetro
            declarado como  VAR. Definiremos neste exemplo, as operaes
            bsicas de  soma e  produto de  matrizes e do produto de uma
            matriz por um escalar.
            
            (* ------------------------------------------------------ *)
            
            PROCEDURE SomaMatrizes(A, B: matriz; VAR S: matriz);
            
            (* Calcula a soma S das matrizes A e B *)
            
            VAR
              i, j: byte;
            
            BEGIN
              (* Checagem se as matrizes so de mesma ordem *)
              if (A.m <> B.m) or (A.n <> B.n) then Exit;
            
              S.m := A.m; S.n := A.n;
              for i := 1 to A.m do
                for j := 1 to A.n do
                  S.a[i, j] := A.a[i, j] + B.a[i, j];

                                       - 119 -





            END;
            
            (* ------------------------------------------------------ *)
            
            PROCEDURE MultPorEscalar(X: matriz; k: real; VAR M: matriz);
            
            (* Calcula M, o produto escalar de k pela matriz X *)
            
            VAR
              i, j: byte;
            
            BEGIN
              M.m := X.m; M.n := X.n;
              for i := 1 to X.m do
                for j := 1 to X.n do
                  M.a[i, j] := k*X.a[i, j];
            END;
            
            (* ------------------------------------------------------ *)
            
            PROCEDURE MultiplicaMatrizes(A, B: matriz; VAR P: matriz);
            
            (* Calcula o produto P das matrizes A e B *)
            
            VAR
              i, j, k: byte;
              soma: real;
            
            BEGIN
              (* Checagem das ordens das matrizes *)
              if (A.n <> B.m) then Exit;
            
              P.m := A.m; P.n := B.n;
              for i := 1 to A.m do
                for j := 1 to B.n do
                begin         (* O termo geral do produto  o somat- *)
                  soma := 0;  (* rio de Aik*Bkj com k variando de 1  *)
                  for k := 1 to A.n do (* quantidade de colunas de A. *)
                    soma := soma + A.a[i, k]*B.a[k, j];
                  P.a[i, j] := soma
                end
            END;
            
            (* ------------------------------------------------------ *)
            
                 "Salve" em  disco os  6 procedimentos  anteriores,  bem
            como a  definio do  tipo matriz  em  um  arquivo  de  nome
            MATRIZES.INC.  Exemplificando  o  uso  desses  procedimentos
            temos o programa a seguir.
            
            PROGRAM OperandoComMatrizes;
            
            {$I MATRIZES.INC}
            

                                       - 120 -





            VAR
              A, B, C: matriz;
            
            BEGIN
              LeMatriz(A, 1, ');
              LeMatriz(B, 1, 'B');
            
              if (A.m = B.m) and (A.n = B.n) then
              begin
                SomaMatrizes(A, B, C);
                Writeln;
                Writeln('A + B = ');
                MostraMatriz(C)
              end;
            
              if (A.n = B.m) then
              begin
                MultiplicaMatrizes(A, B, C);
                Writeln;
                Writeln('AB = ');
                MostraMatriz(C)
              end
            END.
            
                 Um exemplo de execuo  do programinha acima:
            
            Quantidade de linhas da matriz A? 2
            Quantidade de colunas da matriz A? 2
            
            Fornea os elementos da matriz A
            
            Linha 1: -2  1
            Linha 2:  0  3
            
            Quantidade de linhas da matriz B? 2
            Quantidade de colunas da matriz B? 2
            
            Fornea os elementos da matriz B
            
            Linha 1:  3  5
            Linha 2: -1  1
            
            A + B =
            
               1.000   6.000
              -1.000   4.000
            
            AB =
            
              -7.000  -9.000
              -3.000   3.000
            
            

                                       - 121 -





            Exemplo: Para  encerrar esta  seo, antes  das  observaes
            finais, vamos construir mais um procedimento. Neste exemplo,
            queremos um  procedimento que  calcule uma potncia positiva
            de uma matriz.
            
            PROCEDURE CalculaPotencia(X: matriz; expoente: byte;
                                                 VAR M: matriz);
            
            (* Calcula uma potncia M de uma matriz X *)
            
            VAR
              i, j: byte;
              aux: matriz;
            
            BEGIN
              if (X.m <> X.n) then Exit; (* Se a  matriz  X  nao  for *)
                                 (* quadrada,  entao adeus calculo de *)
                                 (* de uma potencia de X.             *)
            
              aux.m := X.m; aux.n := X.n;
              for i := 1 to X.m do       (* Inicialmente, a  matriz *)
                for j := 1 to X.n do     (* auxiliar AUX  defini- *)
                  if (i = j) then        (* da como sendo  a matriz *)
                    aux.a[i, j] := 1     (* identidade.             *)
                  else
                    aux.a[i, j] := 0;
            
              for i := 1 to expoente do           (* A matriz AUX  *)
                MultiplicaMatrizes(X, aux, aux);  (* redefinida como *)
                              (* sendo X*AUX sucessivas vezes. No fi- *)
                              (* nal, AUX ser a potencia  desejada. *)
            
              M := aux;
            END;
            
            Observaes:
            
                 (1)  Podemos   ter  variveis  indexadas  de  dimenses
            maiores que 2. Por exemplo, o TYPE a seguir define variveis
            de dimenses 3 e 4:
            
                 TYPE
                   Paralepipedo = ARRAY [1..3, 1..4, 1..5] OF real;
                   Dimensao4 = ARRAY[1..3, 1..3, 1..3, 1..3] OF integer;
            
                 Nestes casos,  para se  ter acesso  aos  elementos  das
            variveis  desses   tipos  (X,   Y,  ...),   deve-se   fazer
            referncias a elementos como X[i, j, k], Y[1, 2, 3, 1], etc.
            
                 (2) Os  elementos de  uma matriz podem ser de quaisquer
            tipos:  boolean,   string,  registros,  matrizes,  etc.  Por
            exemplo, a tipo MATRIZCHAR abaixo  uma matriz de caracteres
            e o tipo MATRIZDEBLOCOS  uma matriz de matrizes:
            

                                       - 122 -





            TYPE
              MatrizChar = ARRAY [1..4, 1..6] OF char;
              MatrizDeBlocos = ARRAY [1..3, 1..3] OF
                                             ARRAY [1..3, 1..3] OF real;
            
                 (3) As  variveis  indexadas,  como  os  vetores  e  as
            matrizes, podem  ser declaradas  sem o uso do bloco TYPE. No
            entanto, acreditamos  que  esta  no    uma  prtica  muito
            vantajosa para o usurio.
            
                 VAR
                   i, j, k: ARRAY [1..3] OF integer;
                   Mat1, Mat2: ARRAY [1..2, 1..2] of longint;
            
                 (4) Os ndices de uma matriz podem ser de qualquer tipo
            ordinal, inclusive inteiros negativos.
            
                 TYPE
                   MatrizEstranha = ARRAY ['a'..'e', -4..-1] OF string;
            
                 (5) O  tipo string pode ser pensado como sendo um vetor
            de caracteres:
            
                      TYPE
                        string = ARRAY [0..255] OF char;
            
            8.3. SISTEMAS LINEARES    
            
                 Nesta seo  vamos desenvolver  um programa que resolva
            sistemas lineares  determinados.  Antes,  precisamos  de  um
            procedimento que  troque linhas de uma matriz e de outro que
            escalone uma matriz.
            
            PROCEDURE TrocaLinhas(VAR mat: matriz; L1, L2: byte);
            
            (* Troca a linha L1 pela linha L2 na matriz MAT *)
            
            VAR
              aux: real;
              j: byte;
            
            BEGIN
              for j := 1 to mat.n do
              begin
                aux := mat.a[L1, j];
                mat.a[L1, j] := mat.a[L2, j];
                mat.a[L2, j] := aux
              end;
            END;
            
                 Para escalonar uma matriz (a_ij) usaremos o seguinte:
            
                 (1) Inicialmente,  atribumos s variveis LinhaAtual e
            ColunaAtual o valor 1.

                                       - 123 -





                 (2) Atribumos  s variveis  ElementoNaoNulo  o  mesmo
            valor de  LinhaAtual, e   varivel NumeroDeZeros, que conta
            quantos zeros tem em cada coluna, o valor inicial 0.
                 (3) Para  cada linha,  desde a ltima linha da matriz 
            LinhaAtual, contamos  quantos zeros  tem na  ColunaAtual;  o
            resultado da  contagem  guardado na varivel NumeroDeZeros.
            Determinamos tambm  um ndice que corresponda a um elemento
            no nulo  da ColunaAtual; esse ndice  guardado na varivel
            ElementoNaoNulo.
                 (4)  Se  ElementoNaoNulo  for  diferente  do  valor  de
            LinhaAtual,  ento   trocamos  as   respectivas  linhas  que
            correspondam a esses valores.
                 (5) Se NumeroDeZeros for menor do que a diferena entre
            a quantidade  de linhas  da matriz  e o valor de LinhaAtual,
            ento efetuamos  as operaes  de diviso,  multiplicao  e
            subtrao necessrias para se escalonar a matriz: fazemos um
            j variar  desde (LinhaAtual  + 1) at a quantidade de linhas
            da matriz  e, para  cada j,  escolhemos Elem1  como sendo  o
            elemento aj,ColunaAtual,  e  Elem2  como  sendo  o  elemento
            aLinhaAtual,ColunaAtual. Com  um k  variando de  ColunaAtual
            at a  quantidade de  colunas da  matriz,  redefinimos  cada
            elemento    ajk     como    sendo     igual    a    ajk    -
            Elem1/Elem2*aLinhaAtual,k (outra  opo seria  fazer ajk  :=
            Elem2*ajk - Elem1*aLinhaAtual,k ).
                 (6) Se  NumeroDeZeros for  menor  do  que  ou  igual  
            diferena entre  a quantidade  de linhas e LinhaAtual, ento
            incrementamos  de   uma  unidade   o  valor  de  LinhaAtual.
            Incrementamos de uma unidade o valor de ColunaAtual.
                 (7) Se  LinhaAtual for  maior do  que a  quantidade  de
            linhas da  matriz ou  se ColunaAtual  for  maior  do  que  a
            quantidade  de  colunas,  ento  encerramos  o  processo  de
            escalonamento;  caso  contrrio  voltamos  ao  passo  (2)  e
            executamos todas as etapas de (2) a (7) novamente.
            
                 O algoritmo anterior pode ser codificado como a seguir:
            
            PROCEDURE EscalonaMatriz(var mat: matriz);
            
            (* Escalona MAT pelo metodo da eliminacao de Gauss *)
            
            VAR
              i, j, k, LinhaAtual, ColunaAtual,
                       NumeroDeZeros, ElementoNaoNulo: byte;
              Elem1, Elem2, aux: real;
            
            BEGIN
              (* Passo 1 ---> Descrito no algoritmo anterior *)
              LinhaAtual := 1; ColunaAtual := 1;
            
              repeat
                (* Passo 2 *)
                ElementoNaoNulo := LinhaAtual;
                NumeroDeZeros := 0;
            

                                       - 124 -





                (* Passo 3 *)
                for i := mat.m downto LinhaAtual do
                  if (mat.a[i, ColunaAtual] <> 0) then
                    ElementoNaoNulo := i
                  else
                    Inc(NumeroDeZeros);
            
                (* Passo 4 *)
                if (ElementoNaoNulo <> LinhaAtual) then
                  TrocaLinhas(mat, LinhaAtual, ElementoNaoNulo);
            
                (* Passo 5 *)
                if (NumeroDeZeros < mat.m - LinhaAtual) then
                begin
                  for j := LinhaAtual + 1 to mat.m do
                  begin
                    Elem1 := mat.a[j, ColunaAtual];
                    Elem2 := mat.a[LinhaAtual, ColunaAtual];
                    for k := ColunaAtual to mat.n do
                      mat.a[j, k] := mat.a[j, k] -
                                       Elem1/Elem2*mat.a[LinhaAtual, k];
                   (* Outra opcao: ---------------------------------- *)
                   (* mat.a[j, k] := Elem2*mat.a[j, k] -              *)
                   (*                      Elem1*mat.a[LinhaAtual, k] *)
                   (* ----------------------------------------------- *)
                  end;
                end;
            
                (* Passo 6 *)
                if (NumeroDeZeros <= mat.m - LinhaAtual) then
                  Inc(LinhaAtual);
                Inc(ColunaAtual);
            
              until (LinhaAtual > mat.m) or (ColunaAtual > mat.n)
            END;
            
                 Note que  a matriz  que for enviada como parmetro para
            ESCALONAMATRIZ   voltar    escalonada.   Supondo   que   os
            procedimentos   anteriores   esto   gravados   no   arquivo
            ESCALONA.IN ento podemos executar o seguinte:
            
            PROGRAM EscalonamentoDeUmaMatriz;
            
            {$I MATRIZES.INC}
            {$I ESCALONA.INC}
            
            VAR
              m: matriz;
            
            BEGIN
              LeMatriz(m, 1, 'M');
              EscalonaMatriz(m);
              Writeln;
              Writeln('Matriz escalonada: ');

                                       - 125 -





              MostraMatriz(m);     (* Se quisssemos ainda usar a *)
                        (* matriz M  da entrada, deveramos t-la *)
                        (* guardado em uma cpia ( M_aux := m; )  *)
            END.
            
            
                 A soluo do sistema linear
            
                         a_11 x_1 + a_12 x_2 + a_13 x_3 = a_14
                                    a_22 x_2 + a_23 x_3 = a_24
                                               a_33 x_3 = a_34
             dada por:
                           x_3 = a_34/a_33
                           x_2 = (a_24 - a_23 x_3)/a_22
                           x_1 = (a_14 - a_12 x_2 - a_13 x_3)/a_11
            
            (onde aS1kkT <> 0) que pode ser escrita na forma:
            
                              3
                            ----
              x_i = (a_i4 - \      a_ij*x_j) / a_ii , com i = 3, 2, 1.
                            /
                            ----
                           j=i+1
            
                 Esse resultado  vale em  geral para  n variveis: basta
            trocar o 4 acima por n + 1, o 3 por n, e fazer o i variar de
            n at  1. Usaremos  isso na  construo do seguinte procedi-
            mento:
            
            TYPE
              vetor = ARRAY [1..10] of real;
            
            PROCEDURE ResolveSistema(mat: matriz; VAR x: vetor);
            
            (* Resolve o sistema linear determinado cuja matriz
               escalonada  MAT *)
            
            VAR
              i, j: byte;
              soma: real;
            
            BEGIN
              for i := mat.m downto 1 do
              begin
                soma := mat.a[i, mat.m + 1];
                for j := (i + 1) to mat.m do
                  soma := soma - mat.a[i, j]*x[j];
                x[i] := soma/mat.a[i, i]
              end;
            END;
            

                                       - 126 -





                 Para encerrar  o captulo,  um programa exemplo que usa
            RESOLVESISTEMA, que  deve ter  sido adicionada ao arquivo de
            incluso ESCALONA.INC.
            
            PROGRAM SistemasLinearesDeterminados;
            
            USES
              Crt;
            
            {$I MATRIZES.INC}
            {$I ESCALONA.INC}
            
            VAR
              i: byte;
              mat, aux: matriz; (* Matriz completa do sistema *)
              sol: vetor;       (* Solucao do sistema         *)
            
            BEGIN
              Writeln; Writeln;
              Write('Quantidade de variveis do sistema (max = 9) : ');
              Readln(mat.m);         (* Para aumentar a quantidade de *)
              mat.n := mat.m + 1;    (* variveis, basta  aumentar  o *)
              Writeln;               (* tamanho das matrizes          *)
              LeMatriz(mat, 0, 'M');
              aux := mat; (* Cpia da matriz do sistema *)
            
              EscalonaMatriz(aux);
              ResolveSistema(aux, sol);
            
              ClrScr;
              Writeln('MATRIZ COMPLETA DO SISTEMA:');
              MostraMatriz(mat);
              Writeln('Solucao:');
              Writeln;
              for i := 1 to mat.m do
                Write(sol[i]:10:5);
            END.
            
            
                 Podemos  usar  o  programa  anterior  para  resolver  o
            sistema
                                 x +  y + 2z =   3
                                 x - 3y - 2z = -11
                                5x +  y + 4z =   0
            
                 Obtemos, ento, a seguinte resposta:
            
            
            MATRIZ COMPLETA DO SISTEMA:
            
               1.000   1.000   2.000   3.000
               1.000  -3.000  -2.000 -11.000
               5.000   1.000   4.000   0.000
            

                                       - 127 -





            Solucao:
            
              -1.00000   3.00000   0.50000
            
            Observao: Usando  escalonamento de matrizes podemos tambm
            calcular determinantes e inverter matrizes.
            
            
            8.4. EXERCCIOS         
            
            1) Sendo  fornecidos, pelo teclado, 20 valores numricos a1,
            a2, ..., a20, calcule o valor do somatrio
                        a1               a2                    a20
              S = ------------  +  ------------  + ... +  -----------
                  (a20)^2 + 1      (a19)^2 + 1            (a1)^2 + 1
            
            2) Dados 4 vetores V1, V2, V3 e V4, cada um com 50 elementos
            reais  (ou seja, vetores do  R^50), determine um outro vetor
            real W com 50 elementos tal que:
                a)  os elementos  de W  sejam as  mdias aritmticas dos
            elementos de V1, V2, V3 e V4;
                b)  os elementos  de W sejam as mdias aritmticas dos 3
            maiores valores dos elementos de V1, V2, V3 e V4.
            
            3) Elabore um procedimento que multiplique dois polinmios:
                          MultiplicaPolinomios(f, g, p).
        (Lembre-se que p_k = f_0 g_k + f_1 g_k-1 + ... + f_k-1g_1 + f_kg_0 e
         que f_n+1 = f_n+2 = ... = g_m+1 = g_m+2 = ... = 0 se o grau de f
            for n e o grau de g for m)
            
            4) Calcule a transposta de uma matriz M.
            
            5) Gere  aleatoriamente uma matriz cujos elementos sejam -1,
            0 ou 1.
            
            6) Defina uma funo que:
               a) Calcule o trao de uma matriz;
               b) Teste se uma matriz  simtrica;
               c) Teste se uma matriz  diagonal;
               d) Calcule  a soma dos quadrados de todos os elementos de
            uma matriz;
               e) Conte quantos elementos negativos tem uma matriz;
               f) Conte quantas linhas nulas tem uma matriz.
            
                (Em  (a) e  (d) a funo retorna um valor real; em (b) e
            (c), um  valor FALSE  ou TRUE;  em (e)  e (f),  o  valor  de
            retorno  inteiro)
            
            7) Dado  um vetor V de elementos inteiros, possivelmente com
            repetio, determine um vetor W formado pelos elementos de V
            sem repetio. Por exemplo, se
            V = (3, -2, 1, 0, 3, -2, 0, 0, 1, 4, 3, -3, 1, 0, -2, 2, 2),
            ento deveremos ter
                            W = (3, -2, 1, 0, 4, -3, 2).

                                       - 128 -
