Introdução à Programação na linguagem F Jaime Ramos, Amílcar Sernadas e Paulo Mateus DMIST, Setembro de 2005 Capítulo 2 Complementos de programação em F Objectivos Vectores e matrizes. Programação imperativa sobre vectores e matrizes. Programação recursiva sobre vectores. Vectores Para declarar uma variável vectorial, é necessário indicar qual o tamanho do vector em causa e qual o tipo de objectos desse vector. Na instrução seguinte declara-se uma variável v para guardar vectores de números inteiros com tamanho 5: integer, dimension(5) :: v Alternativamente, podia ter sido utilizada a declaração seguinte, em que se delimitam o limite inferior e superior do vector integer, dimension(1:5) :: v Para aceder aos elementos do vector, utiliza-se a expressão v(i), que se refere ao elemento na posição i do vector guardado em v. Pretende-se definir uma função que recebe como argumento um vector de tamanho 5 e retorna a soma dos seus elementos. Como primeira solução, considere-se a seguinte função: function somaVec1(v) result(s) integer, dimension(5), intent(in) :: v integer :: s, i s=0 do i=1,5 s=s+v(i) end do end function somaVec1 Tal como pretendido, esta função recebe como argumento um vector de tamanho 5, soma as suas componentes uma a uma recorrendo a um ciclo do e devolve essa soma. O programa seguinte ilustra a utilização desta função: lê do terminal cinco números inteiros, guarda-os num vector, e calcula a soma dos seus elementos recorrendo à função anterior. program exemplo11 integer, dimension(5) :: v integer :: i do i=1,5 print *,"Introduza um numero:" read *,v(i) end do print *,"O resultado e:",somaVec1(v) contains function somaVec1(v) result(s) integer, dimension(5), intent(in) :: v integer :: s, i s=0 2 do i=1,5 s=s+v(i) end do end function somaVec1 end program exemplo11 Considere-se a seguinte execução: Introduza um numero: 1 Introduza um numero: 2 Introduza um numero: 3 Introduza um numero: 4 Introduza um numero: 5 O resultado e: 15 A pergunta seguinte surge naturalmente: e se pretendermos somar os elementos de vectores com outros tamanhos? Podem surgir duas situações: ou o vector tem tamanho superior a 5 e nesse caso a função apenas soma os cinco primeiros elementos, ou o vector tem tamanho inferior a 5 e nesse caso ocorre um erro de compilação. No entanto a função anterior pode ser generalizada para vectores de qualquer tamanho. O problema da declaração do parâmetro resolve-se recorrendo à declaração: integer, dimension(:), intent(in) :: v Neste caso está-se a declarar um parâmetro que consiste um vector de tamanho arbitrário. O limite do ciclo resolve-se recorrendo à função size. A função seguinte soma os elementos de um vector de números inteiros de dimensão arbitrária: function somaVec(v) result(s) integer, dimension(:), intent(in) :: v integer :: s, I s=0 do i=1,size(v) s=s+v(i) end do end function somaVec O programa seguinte lê seis números inteiros do terminal, guarda-os num vector e, recorrendo à função anterior, soma-os e apresenta o resultado: program exemplo12 integer, dimension(6) :: v integer :: i do i=1,6 print *,"Introduza um numero:" read *,v(i) end do print *,"O resultado e:",somaVec(v) contains function somaVec(v) result(s) 3 integer, dimension(:), intent(in) :: v integer :: s, i s=0 do i=1,size(v) s=s+v(i) end do end function somaVec end program exemplo12 Considere-se a seguinte execução: Introduza um numero: 1 Introduza um numero: 2 Introduza um numero: 3 Introduza um numero: 4 Introduza um numero: 5 Introduza um numero: 6 O resultado e: 21 No próximo exemplo, define-se uma função para contar o número de números primos que ocorrem num vector de números inteiros, recorrendo à função prime definida no capítulo anterior. A função contaP recebe como argumento um vector de números inteiros e devolve o número de números primos que ocorrem nesse vector. O programa seguinte começa por construir um vector com dez números inteiros gerados aleatoriamente (entre 1 e 100) recorrendo à subrotina random, que gera números aleatórios entre 0 e 1. Em seguida chama a função contaP para contar quantos desses números gerados foram números primos. program contaprimos integer, dimension(10) :: v integer :: i real :: x do i=1,10 call random_number(x) v(i)=int(x*100)+1 end do print *,"Numero de primos:",contaP(v) contains function prime(n) result(b) integer, intent(in) :: n logical :: b integer :: i, d if (n<=1) then b= .false. else d=0 do i=2,n-1 if (n-(n/i)*i == 0) then d=d+1 end if end do 4 if (d==0) then b=.true. else b=.false. end if end if end function prime function contaP(v) result(s) integer, dimension(:), intent(in) :: v integer :: s, i s=0 do i=1,size(v) if (prime(v(i))) then s=s+1 end if end do end function contaP end program contaprimos Considerem-se os seguintes exemplos de execução: Numero de primos: 1 Numero de primos: 4 Considere-se agora o problema de calcular o produto interno de dois vectores. A função seguinte calcula o produto interno de dois vectores, desde que eles sejam do mesmo tamanho. No caso de vectores com tamanhos diferentes, o resultado é uma mensagem de erro no ecrã. O valor devolvido neste caso é arbitrário. function prodInterno(v1,v2) result(x) real, dimension(:), intent(in) :: v1,v2 real :: x integer :: i if (size(v1)/=size(v2)) then print *,"Erro! Os vectores nao sao do mesmo tamanho!" else x=0 do i=1,size(v1) x=x+(v1(i)*v2(i)) end do end if end function prodInterno Deixa-se como exercício testar esta função. Considere-se o problema de calcular o produto de um vector por um escalar. A primeira solução consiste numa função que recebe como argumentos o vector v e o escalar x e devolve o vector u resultante do produto do vector pelo escalar, que deverá ser do mesmo tamanho do vector argumento. Como é que se declara esse vector? Através da declaração: integer, dimension(size(v)) :: u A este tipo de declaração, em que o tamanho de um vector é fixado a partir do tamanho de outros argumentos, dá-se o nome de vector automático. Uma solução para a função prodEscalar é a seguinte: function prodEscalar(v,x) result(u) integer, dimension(:), intent(in) :: v 5 integer, intent(in) :: x integer, dimension(size(v)) :: u integer :: i do i=1,size(v) u(i)=v(i)*x end do end function prodEscalar Apresenta-se em seguida um programa para testar esta função. Este programa atribui à variável v o vector (1,2,3,4,5); repare-se na atribuição simultânea de um vector a uma variável. program prodEscalar1 integer, dimension(5) :: v v(1:5)=(/ 1,2,3,4,5 /) print *,prodEscalar(v,2) contains function prodEscalar(v,x) result(u) integer, dimension(:), intent(in) :: v integer, intent(in) :: x integer, dimension(size(v)) :: u integer :: i do i=1,size(v) u(i)=v(i)*x end do end function prodEscalar end program prodEscalar1 O resultado de execução deste programa é: 2 4 6 8 10 Alternativamente, podíamos ter optado por definir uma subrotina. Deixa-se como exercício definir uma subrotina com três parâmetros, dois de entrada, o vector e o número, e um de saída, o vector resultado. Alternativamente, pode definir-se uma subrotina que altera directamente o vector, evitando assim a utilização de dois vectores. Para tal, declara-se o vector como parâmetro de entrada e saída (inout). subroutine prodEscalar(v,x) integer, dimension(:), intent(inout) :: v integer, intent(in) :: x integer :: i do i=1,size(v) v(i)=v(i)*x end do end subroutine prodEscalar O programa anterior pode ser ligeiramente alterado para testar esta subrotina: program prodEscalar2 integer, dimension(5) :: v v(1:5)=(/ 1,2,3,4,5 /) call prodEscalar(v,2) print *,v 6 contains subroutine prodEscalar(v,x) integer, dimension(:), intent(inout) :: v integer, intent(in) :: x integer :: i do i=1,size(v) v(i)=v(i)*x end do end subroutine prodEscalar end program prodEscalar2 O resultado de execução é o mesmo e omite-se. Finalmente, apresenta-se uma subrotina para ordenar vectores de números inteiros (in situ), baseada no método da selecção. Este método consiste em procurar o elemento mínimo e colocá-lo na primeira posição o vector, em seguida procurar o menor elemento do vector de entre os restantes e colocá-lo na segunda posição, e assim sucessivamente. program selsort integer, dimension(5) :: v integer :: i do i=1,5 print *,"Introduza um numero:" read *,v(i) end do call selectSort(v) print *,v contains subroutine swap(v,m,k) integer, dimension(:), intent(inout) :: v integer, intent(in) :: m,k integer :: x x=v(m) v(m)=v(k) v(k)=x end subroutine swap subroutine selectSort(v) integer, dimension(:), intent(inout) :: v integer :: m, k if (size(v)>1) then do m=1,size(v)-1 do k=m+1,size(v) if(v(m)>v(k)) then call swap(v,m,k) end if end do end do end if end subroutine selectSort end program selsort 7 Este programa, para além da subrotina selectSort, utiliza ainda a subrotina swap que permite trocar os elementos nas posições m e k do vector v. Ao executar este programa, obtém-se o seguinte resultado: Introduza um numero: 9 Introduza um numero: 4 Introduza um numero: 7 Introduza um numero: 3 Introduza um numero: 10 Vector ordenado: 3 4 7 9 10 Matrizes A declaração de matrizes é semelhante à dos vectores, mas em vez de apenas uma dimensão, há que considerar duas (ou mais) dimensões. A instrução seguinte permite declarar uma variável m para guardar matrizes 4x3: integer, dimension (4,3) :: m ou, alternativamente, como para vectores: integer, dimension (1:4,1:3) :: m A função pré-definida size continua a poder ser aplicada a matrizes. Neste caso, há que utilizar um segundo argumento indicando a dimensão de que se pretende calcular o tamanho, isto é, size(m,1) permite obter o tamanho da dimensão 1, ou seja, o número de linhas (no caso do exemplo, 4), size(m,2) permite obter o tamanho da dimensão 2, ou seja, o número de colunas (no caso do exemplo, 3). Esta função pode ser aplicada a estruturas de qualquer dimensão. Como primeiro exemplo, apresenta-se uma função para somar todos os elementos de uma matriz. function somaEl(m) result(x) real, dimension(:,:), intent(in) :: m real :: x integer :: i, j x=0 do i=1,size(m,1) do j=1,size(m,2) x=x+m(i,j) end do end do end function somaEl Esta função recorre a dois ciclos encaixados, o primeiro para percorrer as linhas da matriz e o segundo para percorrer as colunas. Para cada valor de i e j, soma-se o valor da entrada correspondente da matriz a x. Esta função foi definida num módulo mmatrices, que inclui outras operações sobre matrizes, apresentadas em seguida. O programa seguinte utiliza esta função para somar os elementos de uma matriz. program testsomaEl real, dimension(3,2) :: m 8 m(1,1)=1 m(1,2)=3 m(2,1)=2 m(2,2)=1 m(3,1)=1.5 m(3,2)=2.5 print *,somaEl(m) contains function somaEl(m) result(x) real, dimension(:,:), intent(in) :: m real :: x integer :: i, j x=0 do i=1,size(m,1) do j=1,size(m,2) x=x+m(i,j) end do end do end function somaEl end program testsomaEl Com efeito, 11.0000000 Tal como no caso dos vectores, podemos definir uma subrotina prodEscalar para multiplicar uma matriz por um escalar. A chamada desta subrotina altera a matriz, ficando o argumento com o resultado da multiplicação da matriz pelo escalar. subroutine prodEscalar(m,x) real, dimension(:,:), intent(inout) :: m real, intent (in) :: x integer :: i,j do i=1,size(m,1) do j=1,size(m,2) m(i,j)=m(i,j)*x end do end do end subroutine prodEscalar Deixa-se como exercício resolver o problema anterior recorrendo a uma função e testar quer a subrotina quer a função. Considere-se agora o problema de somar duas matrizes. Pretendemos definir uma função que receba como argumentos duas matrizes compatíveis (com o mesmo número de linhas e de colunas) e devolva como resultado a matriz resultante da soma. Tal como no caso vectorial, há que declarar a matriz resultado com as mesmas dimensões das matrizes argumento: function somaM(m1,m2) result(a) real, dimension(:,:), intent(in) :: m1,m2 real, dimension(size(m1,1),size(m1,2)) :: a Este tipo de declaração (vectores e matrizes automáticas) já tinha sido utilizado anteriormente, para o caso dos vectores. Note-se, no entanto, que este tipo de declaração apenas pode ser aplicada ao tamanho. O número de dimensões está fixo, ou seja, no caso da matriz a anterior, esta tem sempre duas dimensões (linhas e colunas). A função somaM que soma duas matrizes é a seguinte: 9 function somaM(m1,m2) result(a) real, dimension(:,:), intent(in) :: m1,m2 real, dimension(size(m1,1),size(m1,2)) :: a integer :: i,j if ((size(m1,1)==size(m2,1)).and.(size(m1,2)==size(m2,2))) then do i=1,size(m1,1) do j=1,size(m1,2) a(i,j)=m1(i,j)+m2(i,j) end do end do else print *,"Erro! As matrizes não são da mesma forma" end if end function somaM O programa seguinte testa esta função: program testsomaM real, dimension(3,2) :: m1,m2,m m1(1,1:2)=(/ 3,2 /) m1(2,1:2)=(/ 2,1 /) m1(3,1:2)=(/ 1.5,4.5 /) m2(1,1:2)=(/ 4.5,3.0 /) m2(2,1:2)=(/ 1.2,1.5 /) m2(3,1:2)=(/ 2,3 /) m=somaM(m1,m2) print *,m(1,1),m(1,2) print *,m(2,1),m(2,2) print *,m(3,1),m(3,2) contains function somaM(m1,m2) result(a) real, dimension(:,:), intent(in) :: m1,m2 real, dimension(size(m1,1),size(m1,2)) :: a integer :: i,j if ((size(m1,1)==size(m2,1)).and.(size(m1,2)==size(m2,2))) then do i=1,size(m1,1) do j=1,size(m1,2) a(i,j)=m1(i,j)+m2(i,j) end do end do else print *,"Erro! As matrizes não são da mesma forma" end if end function somaM end program testsomaM Com efeito, 7.5000000 3.2000000 3.5000000 5.0000000 2.5000000 7.5000000 10 Alternativamente, podemos optar por definir uma subrotina que some as duas matrizes, alterando a primeira, que fica com o resultado da soma. subroutine somaM(m1,m2) real, dimension(:,:), intent(inout) :: m1 real, dimension(:,:), intent(in) :: m2 integer :: i,j if ((size(m1,1)==size(m2,1)).and.(size(m1,2)==size(m2,2))) then do i=1,size(m1,1) do j=1,size(m1,2) m1(i,j)=m1(i,j)+m2(i,j) end do end do else print *,"Erro! As matrizes não são da mesma forma" end if end subroutine somaM Neste caso, o resultado da soma de m1 e m2 é deixado em m2, como se comprova com o programa seguinte: program testsomaM1 real, dimension(3,2) :: m1,m2 m1(1,1:2)=(/ 3,2 /) m1(2,1:2)=(/ 2,1 /) m1(3,1:2)=(/ 1.5,4.5 /) m2(1,1:2)=(/ 4.5,3.0 /) m2(2,1:2)=(/ 1.2,1.5 /) m2(3,1:2)=(/ 2,3 /) call somaM(m1,m2) print *,m1(1,1),m1(1,2) print *,m1(2,1),m1(2,2) print *,m1(3,1),m1(3,2) contains subroutine somaM(m1,m2) real, dimension(:,:), intent(inout) :: m1 real, dimension(:,:), intent(in) :: m2 integer :: i,j if ((size(m1,1)==size(m2,1)).and.(size(m1,2)==size(m2,2))) then do i=1,size(m1,1) do j=1,size(m1,2) m1(i,j)=m1(i,j)+m2(i,j) end do end do else print *,"Erro! As matrizes não são da mesma forma" end if end subroutine somaM end program testsomaM1 7.5000000 3.2000000 3.5000000 5.0000000 2.5000000 7.5000000 11 Considere-se agora o problema de pesquisar um elemento numa matriz. A primeira solução capitaliza no facto de pesquisar numa linha ser equivalente a pesquisar num vector. Assim, a solução consiste em utilizar a uma função de pesquisa em vector e aplicá-la a cada uma das linhas. function pesquisaV(x,v) result(b) real, intent(in) :: x real, dimension(:), intent(in) :: v logical :: b integer :: j b=.false. do j=1,size(v) if (x==v(j)) then b=.true. exit end if end do end function pesquisaV Esta função percorre os elementos do vector um a um até encontrar o elemento x e, caso encontre, coloca a variável resultado a .true. e termina a execução do ciclo do (atraves do comando exit). Podemos agora utilizar esta função para pesquisar numa linha de uma matriz. Podemos referir-nos a uma determinada linha i de uma matriz m através da expressão: m(i,1:size(m,2)) assim como nos podemos referir a uma determinada coluna j da mesma matriz através da expressão m(1:size(m,1),j) Assim, pesquisar se um elemento ocorre numa matriz consiste em pesquisar se ele ocorre em alguma das linhas e, caso ocorra, terminar a pesquisa com sucesso. Apresenta-se em seguida uma função para pesquisar um elemento numa matriz, utilizando o método descrito: function pesquisa(x,m) result(b) real, dimension(:,:), intent(in) :: m real, intent(in) :: x logical :: b integer :: i b=.false. do i=1,size(m,1) if (pesquisaV(x,m(i,1:size(m,2)))) then b=.true. exit end if end do end function pesquisa Alternativamente, podíamos ter optado por definir a função de pesquisa anterior sem recorrer à função auxiliar sobre vectores. Esta solução tem a vantagem de não duplicar informação, que resulta de calcular cada uma das linhas para em seguida lhes aplicar a função pesquisaV. Neste caso, há que recorrer a dois ciclos. A pesquisa termina quando se percorrer a matriz toda ou quando se encontrar o elemento. function pesquisa(x,m) result(b) real, dimension(:,:), intent(in) :: m real, intent(in) :: x logical :: b integer :: i, j b=.false. 12 do i=1,size(m,1) do j=1,size(m,2) if (x==m(i,j)) then b=.true. exit end if end do if (b) then exit end if end do end function pesquisa Por fim, considere-se a função para multiplicar duas matrizes, desde que estas sejam compatíveis. Tal como no exemplo anterior, começamos por apresentar uma solução que recorre a uma função auxiliar para calcular o produto interno de uma linha por uma coluna, ou seja, uma função que recebe dois vectores do mesmo tamanho e calcula o respectivo produto interno. function prodLC(l,c) result(x) real, dimension(:), intent(in) :: l,c real :: x integer :: k x=0 do k=1,size(l) x=x+l(k)*c(k) end do end function prodLC Recorrendo a esta função, podemos definir o produto de duas matrizes, desde que estas sejam compatíveis, calculando para cada (i,j) o produto interno da linha i da primeira matriz pela coluna j da segunda matriz. function prodM(m1,m2) result(a) real, dimension(:,:), intent(in) :: m1,m2 real, dimension(size(m1,1),size(m2,2)) :: a integer :: i,j if (size(m1,2)==size(m2,1)) then do i=1,size(m1,1) do j=1,size(m2,2) a(i,j)=prodLC(m1(i,1:size(m1,2)),m2(1:size(m2,1),j)) end do end do else print *,"Erro! As matrizes nao sao compativeis" end if end function prodM Alternativamente, podemos definir a função directamente, como se ilustra em seguida: function prodM(m1,m2) result(a) real, dimension(:,:), intent(in) :: m1,m2 real, dimension(size(m1,1),size(m2,2)) :: a real :: x integer :: i,j,k if (size(m1,2)==size(m2,1)) then do i=1,size(m1,1) do j=1,size(m2,2) x=0 13 do k=1,size(m1,2) x=x+m1(i,k)*m2(k,j) end do a(i,j)=x end do end do else print *,"Erro! As matrizes nao sao compativeis" end if end function prodM Deixa-se como exercício testar as funções anteriores. Programação recursiva Apresentam-se em seguida algumas das funções sobre vectores apresentadas anteriormente, mas desenvolvidas num estilo recursivo. Como já se viu, uma função ou subrotina recursiva deve ser declarada como tal, ou seja, com a declaração recursive. Como primeiro exemplo, considere-se o problema de somar os elementos de um vector. A função somaVecR recebe como argumento um vector e devolve a soma dos seus elementos. Utiliza a função recursiva auxiliar somaVecAux, que tem dois argumentos, um vector e uma posição, e calcula a soma dos elementos do vector a partir da posição dada. Note-se que a soma dos elementos de um vector pode ser definida recursivamente, observando que a soma dos elementos a partir de uma dada posição é o resultado de somar o elemento que está nessa posição com a soma dos elementos nas posições seguintes, isto é: somaVecAux(v,i)=v(i)+somaVecAux(v,i+1) Claro que a expressão anterior apenas se verifica se i for menor ou igual do que o comprimento do vector. Caso exceda este valor, a soma dos elementos do vector deverá ser 0. Apresenta-se em seguida a definição destas duas funções: function somaVec(v) result(x) integer, dimension(:), intent(in) :: v integer :: x x=somaVecAux(v,1) end function somaVec recursive function somaVecAux(v,i) result(x) integer, dimension(:), intent(in) :: v integer, intent(in) :: i integer :: x if (i>size(v)) then x=0 else x=v(i)+somaVecAux(v,i+1) end if end function somaVecAux Deixa-se como exercício testar esta função. Considera-se em seguida o problema de calcular o produto interno de dois vectores. Novamente, considera-se uma função prodInterno, que recorre a uma função recursiva auxiliar prodIntAux para calcular o produto interno de dois vectores a partir de uma determinada posição. Observa-se facilmente que o problema de calcular o produto interno a partir de uma determinada posição pode ser 14 definido recursivamente somando o produto da posição que está a ser considerada dois vectores com o produto interno dos dois vectores a partir da posição seguinte: prodIntAux(v1,v2,i)=v1(i)*v2(i)+prodIntAux(v1,v2,i+1) Novamente, a condição anterior só se verifica se i for menor do que o comprimento dos dois vectores. A função principal deverá começar por testar se os dois vectores são do mesmo tamanho. function prodInterno(v1,v2) result(x) integer, dimension(:), intent(in) :: v1,v2 integer :: x if (size(v1)/=size(v2)) then print *,"Erro! Os vectores nao sao do mesmo tamanho." else x=prodIntAux(v1,v2,1) end if end function prodInterno recursive function prodIntAux(v1,v2,i) result(x) integer, dimension(:), intent(in) :: v1,v2 integer, intent(in) :: i integer :: x if (i>size(v1)) then x=0 else x=v1(i)*v2(i)+prodIntAux(v1,v2,i+1) end if end function prodIntAux Em seguida considera-se o problema de pesquisar um número num vector ordenado. Neste caso, recorrese ao algoritmo de pesquisa binária: sabendo que o vector está ordenado (por ordem crescente), para procurar um elemento x nesse vector basta comparar o elemento com o elemento no meio do vector. Uma de três situações pode acontecer: x é igual ao elemento do meio, e nesse caso termina-se a pesquisa com sucesso; x é maior do que o elemento do meio, e nesse caso basta pesquisar do elemento do meio para a direita; x é menor do que o elemento do meio, e neste caso apenas é necessário pesquisar do elemento do meio para a esquerda. Esta pesquisa é feita recursivamente. Neste caso, no entanto, há que considerar duas posições do vector delimitando os extremos do intervalo do vector onde está a ser efectuada a pesquisa (que podem não coincidir com os extremos do vector). Apresenta-se em seguida a definição da função recursiva para pesquisar se um determinado elemento ocorre entre duas posições de um vector ordenado: recursive function pesquisaAux(x,v,p,u) result(b) integer, intent(in) :: x,p,u integer, dimension(:), intent(in) :: v logical :: b integer :: m if (u<p) then b=.false. else m=(p+u)/2 if (x==v(m)) then b=.true. elseif (x>v(m)) then b=pesquisaAux(x,v,m+1,u) else b=pesquisaAux(x,v,p,m-1) end if end if 15 end function pesquisaAux Esta função é utilizada pela função de pesquisa binária: function pesquisa(x,v) result(b) integer, intent(in) :: x integer, dimension(:), intent(in) :: v logical :: b b=pesquisaAux(x,v,1,size(v)) end function pesquisa Finalmente, conisdera-se o problema de multiplicar um vector por um escalar. Neste caso, optou-se por definir uma subrotina recursiva que altera directamente o vector argumento. Para tal, é necessário definir o parâmetro correspondente ao vector como sendo de entrada e saída (inout). De resto, a subrotina recursiva é em tudo semelhante à função para somar os elementos de um vector. recursive subroutine prodEscalarAux(v,x,i) integer, dimension(:), intent(inout) :: v integer, intent(in) :: x,i if (i==size(v)) then v(i)=v(i)*x else v(i)=v(i)*x call prodEscalarAux(v,x,i+1) end if end subroutine prodEscalarAux A função que calcula o produto escalar utiliza a função auxiliar anterior: subroutine prodEscalar(v,x) integer, dimension(:), intent(inout) :: v integer, intent(in) :: x call prodEscalarAux(v,x,1) end subroutine prodEscalar recursive subroutine prodEscalarAux(v,x,i) integer, dimension(:), intent(inout) :: v integer, intent(in) :: x,i if (i==size(v)) then v(i)=v(i)*x else v(i)=v(i)*x call prodEscalarAux(v,x,i+1) end if end subroutine prodEscalarAux 16