


































































Estude fácil! Tem muito documento disponível na Docsity
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Prepare-se para as provas
Estude fácil! Tem muito documento disponível na Docsity
Prepare-se para as provas com trabalhos de outros alunos como você, aqui na Docsity
Encontra documentos específicos para os exames da tua universidade
Prepare-se com as videoaulas e exercícios resolvidos criados a partir da grade da sua Universidade
Responda perguntas de provas passadas e avalie sua preparação.
Ganhe pontos para baixar
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
PRIMEIRA LIGUAGEM DE PROGRAMAÇÃO
Tipologia: Notas de estudo
1 / 74
Esta página não é visível na pré-visualização
Não perca as partes importantes!



































































1994,
Estes apontamentos foram escritos em 1994 em Wordperfect e posteriormente convertidos em Word. Existirão certamente algumas falhas de conversão não detectadas. O ambiente informático existente à data sofreu entretanto grandes alterações, pelo que se eliminaram alguns tópicos referentes à implementação dos programas propostos. No que se refere à linguagem de programação (Fortran 77 com algumas extensões de Fortran 90) ela permanece utilizável (em Fortran 90/95), sendo no entanto claro que o código poderia ser reescrito de forma um pouco mais elegante. Agradecem-se sugestões e comentários. As fontes (em Fortran) encontram-se disponíveis para download.
Pedro M A Miranda (2004)
http://www.cgul.ul.pt
1 NÚMEROS, OPERAÇÕES E ERROS
Todas as instruções executadas por um computador têm de ser traduzidas em sequências de operações elementares compreendidas pela Unidade de Processamento Central (CPU, i.e., pelo(s) Microprocessador(es)). O leque de instruções elementares disponíveis varia muito de máquina para máquina, dependendo da sua arquitectura e da existência ou não de processadores especializados opcionais (co-processadores aritméticos, nomeadamente). Para o utilizador normal aquilo que se passa a esse nível é, num certo sentido (e felizmente) pouco relevante, dependendo a sua utilização do computador fundamentalmente dos recursos fornecidos pelo software, isto é, pela linguagem de alto nível ou por outra aplicação utilizada.
No entanto, é claro que os recursos oferecidos pelo software são fundamentalmente condicionados pelo modo de operação do computador a um nível mais baixo. Os computadores (digitais) são construídos para obter um elevado grau de eficiência na realização de operações matemáticas sobre números com um número bem determinado de dígitos (na base 2) e segundo regras bem definidas. Nesse contexto só podem ser representados exactamente um subconjunto dos números usuais (inteiros, reais, complexos, etc.) e são de esperar limitações e, eventualmente, erros, nas operações a efectuar.
A afirmação anterior não implica que não possa utilizar-se computadores para realizar operações exactas com números reais ou com qualquer precisão pretendida, mas, tão só, que tais operações serão necessariamente muito menos eficientes. Na verdade existem aplicações que permitem fazer isso mesmo ou até realizar operações simbólicas sobre expressões matemáticas. As linguagens de alto nível, no entanto, limitam-se a oferecer um leque limitado de possibilidades à representação de números e operações.
Internamente, os números são sempre representados em computadores como sequências de algarismos binários (0 ou 1), que correspondem, cada um deles, aos dois estados possíveis do elemento físico elementar em que se encontram armazenados. Quer isto dizer que os números armazenados num computador utilizam como base natural a base binária. Cada algarismo binário, ou a correspondente célula de armazenamento, designa-se geralmente por bit. Todas as operações realizadas por um computador são, por isso, em última análise, operações sobre esses bits e podem ser entendidas como sequências de operações lógicas ( 0 ou 1 é o mesmo que verdadeiro ou falso ), estudadas com base na Álgebra de Boole.
Por motivos práticos é conveniente agrupar os bits em conjuntos. Assim o conjunto de 8 bits designa-se por byte. Se se considerar que um byte constitui um número inteiro na base 2 é claro que um byte poderá representar qualquer número inteiro positivo entre 0 (00000000) e 255 (11111111 = 1× 27 +1× 26 +1× 25 +1× 24 +1× 23 +1× 22 +1× 21 +1× 20 ). Os computadores actuais actuam preferencialmente sobre conjuntos de bytes, sendo os respectivos microprocessadores designados em função do comprimento dos seus registos (16 bits, 32 bits ou 64 bits). As diferentes linguagens permitem definir variáveis com diversos comprimentos (geralmente de 2, 4 ou 8 bytes).
decimal , um pouco mais de 7 algarismos significativos (o número não é exacto nesta base) e um alcance aproximadamente dado por:
Nota-se que neste caso existe um valor máximo absoluto que pode ser representado mas também um valor mínimo absoluto, exceptuando o caso particular do número 0. Assim, são possíveis condições de overflow , quando o resultado de uma operação é um número com valor absoluto excessivamente grande e de underflow , quando esse resultado é um número de valor absoluto excessivamente pequeno. Neste último caso, os compiladores podem arredondar automaticamente para 0.
Contrariamente à aritmética inteira, a aritmética de vírgula flutuante só excepcionalmente produz resultados exactos. Ao erro introduzido pelas limitações de precisão (comprimento finito da mantissa) chama-se geralmente erro de arredondamento ( roundoff ).
Assim, as operações em vírgula flutuante são normalmente afectadas por um erro de arredondamento. Esse erro é inevitável e só pode ser reduzido mediante a utilização de representações com maior precisão, mas nunca eliminado completamente. Numa sequência de operações de vírgula flutuante é de esperar que se observe um crescimento do erro acumulado e pode provar-se estatisticamente que esse crescimento é, em média, inevitável.
Para além do erro de arredondamento, inevitável, que resulta em última análise do hardware utilizado, existe um outro tipo de erro que resulta da utilização de expressões aproximadas (por exemplo, séries truncadas) para a avaliação de um dado resultado. Este tipo de erro é função do software utilizado e designa-se por erro de truncatura. O erro de truncatura pode (e deve) ser controlado pelo programador.
Em certos casos, apesar de as fórmulas utilizadas serem correctas no sentido em que produziriam o resultado exacto com aritmética exacta, o erro pode crescer descontroladamente (exponencialmente) tornando os resultados obtidos completamente inúteis. Tal crescimento resulta de uma interacção entre o erro de arredondamento e o erro de truncatura. Nesse caso diz- se que se está na presença de instabilidade numérica. A principal preocupação da Análise Numérica consiste exactamente em prevenir a ocorrência desta situação.
Um exemplo de obtenção de um resultado afectado de um erro elevado é dado pela utilização da fórmula resolvente usual da equação do segundo grau:
2a
- b b- 4 ac y=
Se b^2 << 4 ac a expressão anterior produzirá um resultado com um erro relativo muito elevado para uma das raízes, devido ao erro de arredondamento. Se b > 0 o erro será muito elevado para a raiz de maior valor (sinal positivo no radical). Caso contrário será a outra raiz a aparecer afectada por um erro elevado. A título de exemplo considere-se a equação:
- y^2 + 8855 y- 1 = 0 (1-6)
Com 7 algarismos significativos, as raízes são:
y=0.00011293 05
y=8855.
2
No entanto, se se utilizar a fórmula resolvente e aritmética truncada a 7 dígitos (i.e. se se arredondar cada resultado parcelar a 7 dígitos) obtém-se:
y =0.00002823 264
y=8855.
2
Verificando-se, portanto, que a raiz de menor valor absoluto vem afectada de um erro extremamente grande, muitíssimo superior ao erro de arredondamento esperado.
O crescimento anormal do erro de arredondamento observado neste exemplo resulta da diminuição do número de algarismos significativos quanto se subtraem dois números de valor muito próximo, visto que o resultado tem uma ordem de grandeza muito inferior à de cada uma das parcelas. Na verdade, a raiz afectada de um erro elevado, é a que resulta da escolha do sinal positivo para o radical presente no numerador da fórmula, ocorrendo a diminuição do número de
algarismos significativos na subtracção: - b+ b^2 - 4ac. É claro que se b fosse negativo o
cancelamento aconteceria na outra raiz.
No caso da equação do segundo grau o problema pode ser evitado se se notar que existe uma fórmula resolvente alternativa, dada por:
- b b- 4ac
2c y = 2 ±
Comparando as expressões (1) e (2) nota-se que se ocorrer cancelamento na primeira raiz da expressão (1) é de esperar cancelamento na segunda raiz da expressão (2). Assim, pode utilizar- se a expressão mais conveniente para calcular cada uma das raízes, evitando o crescimento do erro.
a) O primeiro passo (DECLARAÇÕES) consiste em estabelecer os nomes e as características das diferentes variáveis e constantes que vão ser utilizadas. Dependendo do algoritmo em questão, poderá ser necessário recorrer a variáveis ou constantes que sejam números de tipo INTEIRO, REAL, COMPLEXO, LÓGICO, etc. Nalguns casos, poderá ser necessário utilizar VECTORES ou TABELAS. Por razões de clareza, cada variável deve ser utilizada para um fim bem específico claramente identificado pelo seu nome. Em "linguagem algorítmica" escrever-se-á:
Comentário: DECLARAÇÕES
Reais: s 0 ,v 0 ,s,g,x 1 ,y 1 ,x 2 ,y 2 ,t
b) O segundo passo (INICIALIZAÇÃO) consiste em atribuir valores às constantes e, se necessário, valores iniciais às variáveis. Simbolicamente, indicou-se a operação de atribuição de um dado valor a uma variável pelo símbolo ←. Deve notar-se que a declaração indica unicamente que determinada variável existe e tem o nome e tipo dados mas não lhe atribui qualquer valor.
Comentário: INICIALIZAÇÃO
s 0 ← 10 v 0 ← 20 g ← 9.
c) A inicialização é muitas vezes completada (como é aqui o caso) pela LEITURA de dados.
Comentário: c) LEITURA DE DADOS LER s
d) O passo seguinte é o núcleo central do algoritmo e a sua complexidade e estrutura depende naturalmente do problema. Neste ponto incluir-se-ão, em cada problema, um ou mais BLOCOS de instruções (neste caso será: d1) Cálculo das raízes e d2) Escolha da raiz física), cada um realizando um conjunto de operações bem definido. Por motivos de clareza é conveniente fazer essa separação por blocos sempre que possível, dando ao algoritmo uma forma claramente estruturada e modular.
Primeiro far-se-á o cálculo dos coeficientes da equação:
a ← - 0.5 g b ← v (^0) c ← s 0 -s
d1) O cálculo das raízes será feito mediante utilização da fórmula resolvente da equação do segundo grau. Se se utilizar aritmética complexa, a fórmula pode ser directamente inscrita no
algoritmo. Neste problema vai-se utilizar, em vez disso, aritmética real, pelo que tem de se ter em atenção o sinal do radicando antes de calcular cada raiz. Assim, pode fazer-se:
Comentário: cálculo das raízes da equação do segundo grau
SE b 2 -4ac > 0 ENTÃO x 1 ← (-b+(b 2 -4ac) 1/2^ )/2a x 2 ← (-b-(b 2 -4ac) 1/2^ )/2a y 1 ← 0 y 2 ← 0 SENÃO x 1 ← (-b)/2a x 2 ← (-b)/2a y 1 ← (-b 2 +4ac) 1/2/2a y 2 ← -y 1 FIM DE OPÇÕES
Em muitos casos, a modularidade pode (e deve) ser levada ao ponto de utilizar um algoritmo específico independente (que terá na prática a forma de um sub-programa) para realizar um ou mais dos blocos de instruções. Essa opção tem a vantagem de diminuir a complexidade de cada um dos algoritmos tomado individualmente e de permitir a utilização daquele algoritmo específico noutros problemas. Nesse caso, utiliza-se a expressão EXECUTAR operação , indicando o recurso a um algoritmo independente para a operação indicada. Assim poderia escrever-se em alternativa ao bloco anterior:
EXECUTAR: Calcular xk +i yk tais que a(xk +i yk) 2 +b(xk +i yk )+c = 0
passando o bloco de cálculo das raízes para um algoritmo autónomo.
d2) O bloco seguinte é constituído por uma ESTRUTURA DE CONTROLE extremamente útil em programação que se poderá designar por Estrutura de Escolha Condicional Múltipla (IF- THEN-ELSE), onde é feita a selecção da raiz pretendida. O número de opções a incluir depende do problema.
Comentário: ESCOLHA DAS RAÍZES
SE (y1 ≠ 0 OU y2 ≠ 0) ENTÃO ESCREVA 'Não há Solução' PARE SENÃO SE(x1<0) ENTÃO t ← x 2 SENÃO SE(x2<0) ENTÃO t ← x 1 SENÃO
Vamos fazer o cálculo das raízes utilizando um subprograma genérico (Subroutine Raiz2) para o cálculo de raízes de uma equação do segundo grau qualquer. Utilizar-se-á a segunda estrutura de controle definida em 4.2.
Em FORTRAN, a instrução de atribuição "←" é indicada pelo símbolo "=". A operação lógica de igualdade (comparação) é indicada pela expressão ".EQ.". Existem outras operações de comparação entre números que dão origem a expressões lógicas (i.e., expressões que podem ter valor Verdade (.TRUE.) ou Falso (.FALSE.)):
Operação Significado
A.EQ.B Testa se A é IGUAL a B
A.NE.B Testa se A é DIFERENTE de B
A.LT.B Testa se A é MENOR que B
A.LE.B Testa se A é MENOR OU IGUAL que B
A.GT.B Testa se A é MAIOR que B
A.GE.B Testa se A é MAIOR OU IGUAL que B
Neste programa recorre-se em particular à utilização de um SUBPROGRAMA do tipo SUBROUTINE. Uma SUBROUTINE é, num certo sentido, um programa independente que tem um certo número de valores de entrada (conhecidos no momento em que é iniciada a execução da subroutine) e um certo número de valores de saída (a calcular no interior da subroutine). A sua utilização faz-se do seguinte modo:
a) No programa "principal" escreve-se:
CALL nome_da_subroutine (arg1,arg2,....,argN)
em que nome_da_subroutine representa um nome aceitável pelo fortran (sequência de caracteres alfanuméricos como por exemplo RAIZ2) e arg1,arg2,...,argN representa a sequência de argumentos de entrada e saída, por qualquer ordem (mas idêntica à sua ordem na instrução SUBROUTINE).
b) O subprograma terá a seguinte estrutura:
SUBROUTINE nome_da_subroutine (arg1,arg2,....,argN) (Declarações Instruções ...) RETURN END
C Este Programa determina o tempo de chegada à posição S de um C ponto material lançado de baixo para cima num campo gravítico C com aceleração G (constante) e cuja posição inicial é S C com velocidade V0. C O método utilizado baseia-se na fórmula resolvente da equação C do segundo grau ax2+bx+c=0, cujas raízes são calculadas C na subroutine RAIZ2. C REAL S0,V0,G,S,T,X1,X2,Y1,Y2,A,B,C PARAMETER (S0=10.,V0=20.,G=9.81) C WRITE(,) 'Programa GRAVE' WRITE(,) 'Calculo do tempo de queda de um ponto material' WRITE(,) 'Indique o valor de S (posição final)' READ(,) S C A=-0.5G B=V C=S0-S C CALL RAIZ2(A,B,C,X1,X2,Y1,Y2) C IF(Y1.NE.0. .OR. Y2.NE.0.) THEN WRITE(,) 'Não há solução' STOP ELSE T=MIN(X1,X2) IF(T.LT.0.) THEN T=MAX(X1,X2) ENDIF ENDIF C WRITE(,) 'Solução: t=',T STOP END C C C SUBROUTINE RAIZ2(A,B,C,R1,R2,I1,I2) C C Esta subroutine calcula as raízes C1=R1+iI1, C2=R2+iI C da equação do segundo grau ax*2+bx+c=0, utilizando a
Teste o Programa apresentado comparando-o com resultados analíticos para os casos: a)
s 0 <s< s max ; b)^ s^ =s max ; c)^ s^ <s 0 ; d)^ s^ >s max.
Modifique o programa utilizando aritmética complexa.
Modifique o programa utilizando a estrutura de controle d2 definida em 4.2.
a) Programa principal (PROGRAM, END)
b) Declarações (REAL)
c) Definição de parâmetros constantes (PARAMETER)
d) Utilização de subprogramas
Subroutine (CALL, SUBROUTINE, RETURN)
Transferência de argumentos
Carácter local das variáveis
e) Estrutura de escolha condicional múltipla (IF-THEN-ELSE, ENDIF)
f) Leitura e escrita no terminal (WRITE(,), READ(,))
g) Funções intrínsecas: ABS(),MIN(),MAX(),SQRT()
3 AJUSTAMENTO DE DADOS EXPERIMENTAIS POR
REGRESSÃO LINEAR
Vamos considerar o problema da determinação da constante de Planck h , a partir de dados obtidos numa experiência com uma célula fotoeléctrica, que consistem numa série de valores do potencial de paragem (^) V (^) P , em função do comprimento de onda da luz incidente na célula.
de conservação da energia pode escrever-se:
e (^) VP=h ν - W (3-1)
em que (^) W é a chamada energia de arranque da célula, considerada constante para cada célula.
O problema consiste, portanto, em: dados ( (^) VP (^) i, ν (^) i)(i=1,2,...,N) , calcular a melhor aproximação
possível (num sentido a definir) para h. A solução do problema fornecerá igualmente um valor para W.
O problema referido é um exemplo de uma família muito extensa de problemas de física (e não só) que se pode reduzir ao problema da determinação dos parâmetros de uma recta (declive e ordenada na origem) que "melhor" se ajusta a uma série de dados.
Formalmente pode escrever-se: Dados ( (^) xi ,yi)(i=1,2,...,N) , calcular a e b tais que a recta
y =ax+ b , é a que melhor se ajusta aos dados (num sentido a definir).
A solução geralmente utilizada para este problema consiste em escolher os parâmetros da recta que levam à minimização do erro médio quadrático:
[ (^) y- ( ax+b )] N
=^1 e (^) i i^2
N i=
Impondo a condição de minimização, i.e., resolvendo as duas equações:
( ) ( (^) e ) = 0 b e = a
2 2 ∂
∂ ∂
obtém-se:
( ) (^) ( (^) x ) N
x
x y N
x y- a= i
2 2 i
i i i i
S S +x^ y
S S +x
S S+y
S S +x
xy xy i i
xx xx^2 i
y y i
x x i
←
←
←
←
Fim de ciclo
N^ S
-^1 S
NS S
-^1 S a xx^2 x
xy x y ←
( (^) S -aS ) N
b 1 ← y x
Escrever a,b FIM
a) A tradução do algoritmo anterior em Fortran é razoavelmente simples. Na sequência de comentário feito anteriormente, vai adoptar-se dupla precisão (64 bits, i.e., 8 bytes) para o cálculo dos somatórios e do resultado final. As variáveis correspondentes terão, por esse motivo de ser declaradas utilizando a instrução DOUBLE PRECISION (ou REAL*8).
b) Este programa vai ainda utilizar duas sequências de valores reais, i.e., dois vectores. Em Fortran, a declaração de um vector real X faz-se pela instrução
REAL X(n)
em que n é o número de elementos do vector. Alternativamente pode escrever-se:
REAL X DIMENSION X(n)
Podem declarar-se vectores de qualquer tipo (REAL, INTEGER, LOGICAL, COMPLEX, CHARACTER) e podem declarar-se variáveis com índices múltiplos (e.g. DIMENSION X(n,m,k)).
c) Dado que o número de pontos experimentais pode ser grande vai admitir-se que eles foram previamente escritos num ficheiro permanente (em disco). Esse facto obriga à introdução de formas mais elaboradas da instrução de leitura READ. A instrução READ (assim como a instrução de escrita WRITE) tem a forma:
READ(unidade,formato[,END=label1,ERR=label2,...]) variáveis
em que os parâmetros no interior de [] são opcionais.
O parâmetro "unidade" é um valor inteiro que identifica uma determinada unidade de leitura. Se se escrever o símbolo "*" a leitura será feita sobre a "unidade por defeito" que é o teclado. Se se
utilizar um número de unidade o seu significado, i.e., a sua correspondência a um dado ficheiro, ao teclado, à impressora, etc., terá de ser previamente estabelecida por intermédio de uma instrução de abertura da unidade que tem a forma:
OPEN(unidade,FILE='nome_do_ficheiro',[STATUS='OLD',...])
Assim, poderia escrever-se, por exemplo:
OPEN(10,FILE='PLANCK.DAT') READ(10,*) N
O segundo parâmetro da instrução READ, referido como o "formato" inclui informação referente à forma de cada uma das linhas a ser lida, i.e., à disposição dos algarismos e textos nessa linha. Se se utilizar o formato "*" o sistema será capaz de reconhecer as diferentes variáveis se elas estiverem separadas entre si por espaços, vírgulas ou mudanças de linha, com as variáveis CHARACTER delimitadas por plicas (').
d) Na escrita dos resultados, utilizar-se a instrução WRITE com um formato.
C Março 1993 C Este programa faz uma regressão linear C A partir de um conjunto de N pares (x,y) calcula uma recta C y=ax+b, que melhor se ajusta a esses dados no sentido dos C mínimos quadrados C INTEGER NMAX,N,I PARAMETER(NMAX=1000) REAL X(NMAX),Y(NMAX) CHARACTER*30 FNAME,FORM DOUBLE PRECISION SX,SY,SXX,SXY,A,B,ELECT PARAMETER(ELECT=1.602D-19)
WRITE(,) 'Regressão linear y=ax+b' WRITE(,) 'Ficheiro de dados de entrada' READ(*,'(A30)') FNAME OPEN(10,FILE=FNAME,STATUS='OLD')
READ(10,) N IF(N.GT.NMAX) THEN WRITE(,*) 'ERRO: N>NMAX' STOP ENDIF
DO I=1,N READ(10,*) X(I),Y(I)