• Nenhum resultado encontrado

Professor: Anibal Leonardo Pereira última atualização: março 2011

N/A
N/A
Protected

Academic year: 2019

Share "Professor: Anibal Leonardo Pereira última atualização: março 2011"

Copied!
75
0
0

Texto

(1)

Física Computacional A

DFAT/

FiscompFA

Sistemas Lineares

Professor: Anibal Leonardo Pereira

última atualização: março 2011

Estagiários:

2004/1 a 2005/2

Luciana Conceição Iecker Lima

2010/1

Magali dos Santos Leodato

2009/1 a 2010/2

Filipe da Fonseca Cordovil

Monitores:

2001/1

Diego Chagas Garcia

2002/2

Erick Azevedo Meirelles

2003/1 a 2003/2

Luciana Maria dos Santos Azevedo

2003/1 a 2003/2

Tatiana Gonçalves Martins

2003/1 a 2005/2

Renato Nascente Júnior

2004/1 a 2005/2

Públio Martins Romano M. Carreiro

2006/1 a 2007/2

Luiz Fernando Rosalba Telles Souza

2006/1 a 2007/2

Paulo Henrique Pfitzner

2008/1 a 2008/2

Filipe da Fonseca Cordovil

2008/1 a 2009/2

Magali dos Santos Leodato

2011/1 a

Filipe da Fonseca Cordovil

1. Sistemas Lineares

Problemas de interesses práticos em Física e Engenharia muitas vezes acabam levando a um conjunto de

equações lineares

(sistema de equações lineares

). De posse do sistema linear, a solução do problema que está sendo

tratado é obtida resolvendo-se o sistema de equação. Por exemplo, considere o circuito elétrico mostrado a seguir:

deseja-se calcular as voltagens nos nós 1, 2, 3 e 4. Para isto procede-se assim:

Lei de Kirchhoff (lei dos nós)

Em qualquer nó, a soma das correntes que entram (

apontam para o nó

) é igual

à soma das correntes que partem dele:

n entram

i

n

=

p saem

i

p

Nó é um ponto onde elementos são ligados

Admitindo que as correntes, em cada nó, estejam entrando, pode-se escrever as seguintes

equações:

nó 1

:

i

a1

i

21

i

41

=

0

nó 2

:

i

12

i

32

=

0

nó 3

:

i

23

i

43

=

0

(2)

Usando a lei de Ohm e substituindo nas equações dos nós obtidas anteriormente, tem-se:

nó 1:

100

V

1

R

1

V

2

V

1

R

2

V

4

V

1

R

5

=

0

nó 2:

V

1

V

2

R

2

V

3

V

2

R

3

=

0

nó 3:

V

2

V

3

R

3

V

4

V

3

R

4

=

0

nó 4:

V

1

V

4

R

5

V

3

V

4

R

4

b

V

4

R

6

=

0

Se as resistências têm valores

R

1

=

10

, R

2

=

2

, R

3

=

4

, R

4

=

6

, R

5

=

8

, R

6

=

10

chega-se ao

seguinte sistema de equações:

29

40

V1 +

1

2

V2 +

1

8

V4 = −10

1

2

V1 -

6

8

V2 +

1

4

V3 = 0

1

4

V2 -

10

24

V3 -

1

6

V4 = 0

1

8

V1 +

1

6

V3 -

47

120

V4 = 0

Observe que este sistema de equações é composto por 4 equações e 4 incógnitas (

V

1

,

V

2

,

V

3

,

V

4

). A

solução deste sistema de equações leva às voltagens em cada um dos nós.

De uma forma geral um sistema de 4 equações e 4 incógnitas pode ser escrito assim:

{

a

11

x

1

a

12

x

2

a

13

x

3

a

14

x

4

=

b

1

a

21

x

1

a

22

x

2

a

23

x

3

a

24

x

4

=

b

2

a

31

x

1

a

32

x

2

a

33

x

3

a

34

x

4

=

b

3

a

41

x

1

a

42

x

2

a

43

x

3

a

44

x

4

=

b

4

Sob a forma matricial, este sistema de equações pode ser escrito como

A

x

=

b

[

a

11

a

12

a

13

a

14

a

21

a

22

a

23

a

24

a

31

a

32

a

33

a

34

a

41

a

42

a

43

a

44

]

[

x

1

x

2

x

3

x

4

]

=

[

b

1

b

2

b

3

b

4

]

onde

A é a matriz quadrada de ordem n

(

no exemplo n=4, mas n pode ser qualquer valor, para o caso geral

)

b

e

x

são matrizes n x 1 (

isto é, uma matriz com n linhas e uma coluna

).

Os valores

a

ij

são chamados de coeficientes das incógnitas

x

j

enquanto os

b

i

são chamados de termos

independentes.

(3)

Uma forma bastante compacta de escrever as

n equações

com

n incógnitas

, é:

j=1

n

a

ij

x

j

=

b

i

,

i

=

1 , 2, 3 ,

,

n

A matriz A é chamada matriz dos coeficientes enquanto a matriz

B

=

[

a

11

a

11

...

a

1n

b

1

a

21

a

22

...

a

2n

b

2

...

...

... ...

...

a

n1

a

n2

...

a

nn

b

n

]

é chamada de

matriz aumentada

ou matriz estendida do sistema.

Os números

x

1

,

x

2

,

,

x

n

constituem uma solução do sistema de equação. Isto significa que ao substituir

estes números (

a solução

) no sistema de equação, as equações se transformam em igualdades numéricas.

Os números

x

1

,

x

2

,

,

x

n

formam uma matriz coluna

x

=

[

x

1

x

2

x

n

]

que é chamada de matriz solução do

sistema de equação.

2. Sistema Determinado e Sistema Singular

Um sistema de equações lineares (

sistema linear

) é classificado como sendo:

determinado

quando apresenta solução única (

ou não singular

)

indeterminado

se existem inúmeras soluções

impossível

ou

singular

se não existe solução

Para facilitar o entendimento do sistema linear:

considere o sistema linear:

{

20

x

1

10

x

2

=

15

16

x

1

6

x

2

=

11

ele é um sistema

determinado

pois tem solução única

x

1

=

x

2

=

0.5

.

Geometricamente, pode-se interpretar o sistema de

equações lineares como sendo retas no plano

x

1

0

x

2

,

como mostrado na figura ao lado.

(4)

Sistema singular

:

Neste exemplo pode-se ver na figura que o sistema (

composto por duas retas

) não possui solução (

não se cruzam

), sendo portanto

um sistema linear

impossível

(

sem solução

).

Sistema singular

:

Agora as duas equações são paralelas e estão colocadas uma

sobre a outra, por isto o sistema linear é um sistema

indeterminado

(

infinitas soluções

).

Sistema Homogêneo

O sistema linear

{

a

11

x

1

a

12

x

2

⋯

a

1n

x

n

=

b

1

a

21

x

1

a

22

x

2

⋯

a

2n

x

n

=

b

2

⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯

a

n1

x

1

a

n2

x

2

⋯

a

nn

x

n

=

b

n

que tem

b

i

=

0,

i

=

1,2

,

, n

, isto é, a matriz

b

=

0

, é dito homogêneo.

Todo sistema homogêneo é determinado

, pois sempre admite a solução zero, isto é,

x

i

=

0,

i

=

1,2

,

, n

ou seja, a matriz

x

=

0

.

Sistema Singular

Um sistema linear do tipo

{

a

11

x

1

a

12

x

2

⋯

a

1n

x

n

=

b

1

a

21

x

1

a

22

x

2

⋯

a

2n

x

n

=

b

2

⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯

a

n1

x

1

a

n2

x

2

⋯

a

nn

x

n

=

b

n

é dito singular se o determinante da matriz A

é nulo

det A

=

0

.

Característica importante:

Sistemas indeterminados e impossíveis têm determinante nulo.

3. Sistemas Triangulares

Uma matriz é chamada de triangular quando os elementos acima ou abaixo da diagonal principal são zeros.

(5)

Veja o exemplo, considere o sistema linear:

{

3

x

1

+

4

x

2

-

5

x

3

+

x

4

=

10

x

2

+

x

3

- 2

x

4

=

1

4

x

3

-

5

x

4

=

3

2

x

4

=

2

na forma matricial

A

x

=

b

este sistema fica assim:

[

3 4

5

1

0 1

1

1

0 0

4

5

0 0

0

2

]

[

x

1

x

2

x

3

x

4

]

=

[

10

1

3

2

]

A solução deste sistema triangular superior é encontrada por

substituições retroativas

, então:

x

4

=

1

4

x

3

5

1

=

3

x

3

=

2

x

2

2

2

1

=−

1

x

2

=−

1

2

x

1

4

−

1

5

2

1

=−

10

x

1

=

1

então a

solução

deste sistema linear é:

x

=[

1

1 2 1

]

T

x

=

[

1

1

2

1

]

. Portanto o sistema tem solução, o

sistema é determinado.

Analogamente os sistemas lineares que tem a

forma triangular inferior

podem ser resolvidas por

substituição

progressiva

. Veja o exemplo.

{

2

x

1

=

1

8

x

1

1

x

2

=

5

5

x

1

3

x

2

2

x

3

= 10

ou na forma matricial

[

2

0 0

8

1 0

5

3 2

]

[

x

1

x

2

x

3

]

=

[

1

5

10

]

as

substituições progressiva

são:

x

1

=

0.5

8

0.5

– x

2

=

5

x

2

=−

1

−

5

0.5



3

−

1



2

x

3

=

10

x

3

=

7.75

portanto a

solução

do sistema linear é:

x

=[

0.5

1 7.75

]

T

(6)

4. Propriedades das Matrizes

matriz m x n

uma matriz pode ter um número qualquer de linhas e colunas.

O número de linhas não necessariamente deve ser igual ao número de colunas

m x n → (

lê-se matriz m por n

) indica uma matriz com m linhas e n colunas

matriz quadrada → n x n

matriz linha

→ m x 1

matriz coluna

→ 1 x n

igualdade de matriz

duas matrizes são iguais se e somente se

tem a mesma forma

cada elemento correspondente nas duas matrizes são iguais

por exemplo, as matrizes A e B são iguais

A

=

[

2

0 0

8

1 0

5

3 2

]

e

B

=

[

2

0

0

2

×

4

1

0

5

3 8

÷

4

]

soma de duas matrizes

só é possível quando as matrizes têm a mesma forma

matriz cujos elementos é a soma dos dois elementos correspondentes nas matrizes originais

a matriz

C

=

[

6

0 9

8

1 7

3

3 1

]

pode ter sido obtida da adição de suas matrizes: C = A + B

[

6

0 9

8

1 7

3

3 1

]

=

[

2

0 15

7

2

5

2

5

1

]

[

4

0

6

1

1

2

1

2

0

]

diferença de duas matrizes

só é possível quando as matrizes têm a mesma forma

matriz cujos elementos é a diferença dos dois elementos correspondentes nas matrizes originais

exemplo: C = A - B

[

3

0 6

8

1 7

3

3 1

]

=

[

5

0 10

9

2

9

4

5

1

]

[

2

0 4

1

1 2

1

2 0

]

produto de número escalar por matriz

C

=

2

×

A

[

6

0 9

8

1 7

3

3 1

]

=

2

×

[

3

0

4.5

4

0.5 3.5

1.5

1.5 0.5

]

matriz identidade

matriz quadrada cujos elementos da diagonal principal são unitários e todos os outros elementos da matriz

são zero

I

=

[

(7)

transposta de uma matriz

a matriz

A

T

onde as linhas e colunas de

A

trocam de posição, então:

A

=

[

1 2 3

4

5 6

7 8 9

]

;

A

T

=

[

1 4 7

2

5 8

3 6 9

]

produto de matriz

o produto de duas matrizes está definido se o número de colunas da primeira coluna é igual ao número de

linhas da segunda matriz:

matriz A com (m x

n)

matriz B com (

n

x p)

gerando uma matriz do tipo (

m x p

)

cada termo da matriz produto é definido por:

c

ij

=

k=1

n

a

ik

b

ik

exemplo: A x B = C

A

(2 x 3)

B

(3 x 2) →

C

(2 x 2)

[

1

2 0

3

4 1

]

×

[

1 2

1 1

0 1

]

=

[

1 4

7

3

]

observe como é feita a operação:

Importante:

(8)

5. Número Aleatório

O padrão Fortran permite o uso de dois esquemas diferentes para gerar números aleatórios.

Esquema com mesma semente

Este é o

esquema mais utilizado

pelos compiladores. Nele, o processador inicializa a semente do gerador de

número pseudo-aleatório sempre com o mesmo valor no início da execução. Isto produzirá a mesma sequência de

números aleatórios cada vez que o programa é executado.

Esquema com semente diferente

O segundo esquema permitido pelo padrão (

utilizado por poucos compiladores

) é aquele em que o gerador de

número pseudo-aleatório é inicializado com uma semente diferente no início da cada execução, produzindo uma

sequência de números aleatórios diferentes cada vez que o programa é executado. Neste caso, se houver a

necessidade de se gerar a mesma sequência de números aleatórios é necessário guardar (

salvar

) a semente

(

geralmente num arquivo de dados

) para que ela possa ser reutilizada quando necessário.

O compilador

gfortran

, utilizado na disciplina, gera sempre a mesma semente para o gerador de número

aleatório. O programa

mesma_sequencia

. Permite evidenciar isto.

program mesma_sequencia

!--- !Este programa gera sempre a mesma sequência de números aleatórios ! Arquivo: mesma_sequencia.f03

! AUTOR: Anibal L. Pereira 17/02/2011

!--- --- implicit none

real:: x integer::i print* do i=1,10

call random_number(x)

print"(a,i2,a,f5.3)"," i = ",i," --> ", x end do

end program mesma_sequencia

Execute algumas vezes o programa e veja as saídas !

Para gerar uma sequência diferente é necessário iniciar a semente do gerador de número aleatório com um valor

diferente. Uma forma prática de fazer isto é, usar o relógio do computador. Pegar-se o tempo que o relógio registra

para gerar a semente que inicia o gerador de número aleatório. O programa

sequencia_diferente

mostra isto.

A sub-rotina intrínseca system_clock conta o tempo em segundos de um relógio de parede

desde a zero hora de primeiro de janeiro de 1970 (

00:00:00 UTC, january 1 1970

).

O resultado é escrito num inteiro de precisão simples (

count

).

Informações sobre “

Unix Time”

, para ajudar em um melhor entendimento da sub-rotina

system_clock, pode ser obtido em:

(9)

Declarações para gerar sequência de números aleatórios diferentes

program sequencia_diferente

!--- !Este programa gera uma sequência de números aleatórios diferente !cada vez que é executado

! Arquivo: sequencia_diferente.f03 ! AUTOR: Anibal L. Pereira 17/02/2011

!--- implicit none

real:: x integer::i

integer:: NRI, NRN, NRR !número aleatório – semente aleatória----+ integer, allocatable, dimension(:):: NRS ! !---+ !---número-aleatório --- gera semente aleatória ---+ call random_seed(size = NRN) ! allocate( NRS(NRN) ) ! call system_clock(count = NRR) ! NRS = NRR + 37 * [ (NRI - 1, NRI = 1, NRN) ] ! call random_seed(put = NRS) ! deallocate(NRS) ! !---+ !--- executa a sub-rotina com a semente aleatória

print* do i=1,10

call random_number(x)

print"(a,i2,a,f5.3)"," i = ",i," --> ", x end do

end program sequencia_diferente

Forma simplificada

program NR_forma_simples

!--- !Gera sequência de números aleatórios diferente quando é executado ! Arquivo: NR_forma_simples.f03

! AUTOR: Anibal L. Pereira 17/02/2011

!--- implicit none

real:: x integer::i

integer:: NRI, NRN, NRR !número aleatório – semente aleatória----+ integer, dimension(8):: NRS ! !---+ !---nova semente ---+ call system_clock(count = NRR) ! NRS = NRR + 37 * [ (NRI - 1, NRI = 1, 8) ] ! call random_seed(put = NRS) ! !---+ print*

do i=1,10

call random_number(x)

print"(a,i2,a,f5.3)"," i = ",i," --> ", x end do

(10)

Melhor forma

A forma mais conveniente de gerar sequências de números aleatórios diferentes em cada execução é utilizando

uma sub-rotina que gere as sementes diferentes. Exemplo:

program sequencia_diferente_com_modulo

!--- !Gera sequência de números aleatórios

!diferente

! Arquivo: sequencia_diferente_com_modulo.f03 ! AUTOR: Anibal L. Pereira 17/02/2011 !--- use m_numero_aleatorio

implicit none real:: x integer::i

call semente_diferente() print*

do i=1,10

call random_number(x)

print"(a,i2,a,f5.3)"," i = ",i," --> ", x end do

end program sequencia_diferente_com_modulo

module m_numero_aleatorio

!--- !Contém sub-rotina semente_diferente

! Arquivo: m_numero_aleatorio.f03

! AUTOR: Anibal L. Pereira 17/02/2011 !--- contains

subroutine semente_diferente() integer:: i, n, relogio

integer, allocatable, dimension(:):: semente

call random_seed(size = n) allocate(semente(n))

call system_clock(count = relogio) semente=relogio + 37 * [ (i-1, i=1,n) ] call random_seed(put = semente)

deallocate(semente)

end subroutine semente_diferente end module m_numero_aleatorio

Usando sub-rotina interna

program sequencia_diferente_sri

!--- !Gera sequência de números aleatórios diferente ! Arquivo: sequencia_diferente_sri.f03

! AUTOR: Anibal L. Pereira 17/02/2011

!--- implicit none

real:: x integer::i

call semente_diferente() print*

do i=1,10

call random_number(x)

print"(a,i2,a,f5.3)"," i = ",i," --> ", x end do

contains

!--- subroutine semente_diferente()

integer:: i, n, relogio

integer, dimension(8):: semente call random_seed(size = n)

call system_clock(count = relogio)

semente=relogio + 37 * [ (i - 1, i = 1, n) ] call random_seed(put = semente)

end subroutine semente_diferente

(11)

Números no Fortran, por default, são definidos e utilizados como sendo de precisão simples. Números reais

(

aqueles que possuem parte decimal

) possuem uma representação interna diferente dos números inteiros, no

computador. Este conhecimento é muito importante e não pode ser esquecido ou desconsiderado.

Números do tipo inteiro

Qualquer número é representado internamente no computador na forma binária. Números binários só pode

conter dois valores (

0

ou

1

) em cada dígito utilizado. Veja a representação dos números 0 a 5 na forma binária:

binário decimal

00000000 0

00000001 1

00000010 2

00000011 3

00000100 4

00000101 5

O número binário foi escrito usando somente um

byte

(

octeto

) [

para ser mais facilmente visualizado

].

Um octeto possuí 8 posições (

8 bits

) onde se pode escrever um dígito binário (

digito 0 ou digito 1

), portanto é do

tipo:

00000000

Entretanto, quando o fabricante projeta uma CPU (

central processor unit

) ele tem que tomar uma decisão de

quantos bits a sua CPU vai utilizar para trabalhar com os números. Esta decisão é importante porque ela afeta o

projeto e construção dos circuitos eletrônicos utilizados na CPU. Ao fazer esta escolha o tamanho da palavra do

computador (

da CPU

) fica definido. O tamanho da palavra define quantos bits (

portanto quantos octetos – bytes

) serão

utilizados na representação dos números (

4 octetos= 32 bits, 8 octetos = 64 bits, etc.

).

Atualmente as CPU's modernas utilizam palavras de 8 octetos (

64 bits

). Entretanto, como muitos dos softwares

ainda em uso foram escritos para computadores de palavra de 32 bits, mesmo os computadores modernos tendo

palavra de 64 bits trabalham como se tivessem palavra de 32 bits (

por causa do software utilizado

). Tudo isto muda

quando se utiliza softwares escritos em 64 bits para serem utilizados com computadores com palavra de 64 bits.

Para os computadores que utilizam softwares de 32 bits ou foram construídos com palavra de 4 octetos (

32 bits

)

os números são escritos internamente assim (

apresenta-se a palavra de 32 bits por que é visualmente mais agradável de ser vista

):

00000000000000000000000000000000 (com 32 bits)

Por isto a representação dos primeiros 5 inteiros são escritos (

internamente ao computador

) assim:

binário

decimal

00000000000000000000000000000000 0

00000000000000000000000000000001 1

00000000000000000000000000000010 2

00000000000000000000000000000011 3

00000000000000000000000000000100 4

00000000000000000000000000000101 5

Isto é o que se entende por precisão simples. Nos computadores de 32 bits, precisão simples significa números

inteiros representados internamente com 32 bits.

Ao utilizar 32 bits e esta forma de representação dos números pode-se utilizar números inteiros positivos que

vão de 0 a +4294967296.

00000000000000000000000000000000

zero

11111111111111111111111111111111

+4294967296

(12)

Por este motivo, a técnica utilizada para escrever números inteiros negativos é separar o primeiro bit para ser

utilizado como sinal. Isto resolve o problema, mas deixa somente 31 bits para serem utilizados no número, o que

faz com que menos números inteiros possam ser representados de -2.147.483.648 a +2.147.483.647. Com esta

técnica, os números inteiros são representados internamente assim:

s

0000000000000000000000000000000

números inteiros positivos

00000000000000000000000000000000

0 com o bit do sinal s = 0

00000000000000000000000000000001

+1

00000000000000000000000000000010

+2

00000000000000000000000000000011

+3

00000000000000000000000000000011

+4

números inteiros negativos

10000000000000000000000000000000

-0 com o bit do sinal s = 1

10000000000000000000000000000001

-1

10000000000000000000000000000010

-2 (

geralmente o valor -0 é igual ao +0

)

10000000000000000000000000000011

-3

10000000000000000000000000000011

-4

Caso queira representar números inteiros maiores de +2147483647 ou menores que -2147483648 é necessário

utilizar o que se chama precisão dupla.

precisão simples

= 32 bits (4 octetos) [

para os computadores com palavra de 32 bits

]

precisão dupla

= 64 bits (8 octetos) [

para os computadores com palavra de 32 bits

]

A representação interna do número -5 será assim:

precisão simples:

10000000000000000000000000000100

precisão dupla:

1000000000000000000000000000000000000000000000000000000000000100

Utilizando a precisão dupla pode-se utilizar números inteiros na faixa:

−9223372036854775808 a +9223372036854775807

Números do tipo real

Nos computadores de 32 bits a precisão simples utiliza 32 bits

A representação interna de números reais é completamente diferente da representação interna dos números

inteiros. A representação interna de números do tipo

real de precisão simples

com sinal é feita assim:

Figura 01

– Representação interna do número real precisão simples +0.15625

(13)

Observe as seguintes características:

sinal:

1 bit

O sinal é guardado no bit 31 (

dos 32 bits – 4 octetos utilizados para representar internamente o número real

)

expoente:

8 bits

O expoente é guardado em 8 bits que vai do bit 23 a bit 30

fração:

23 bits

A fração [

também chamado de: significando (signiticand), coeficiente, principal ou mantissa]

O número real de precisão simples utiliza 1 bit para o sinal, 8 bits para o expoente e 24 (

apenas 23 são explicitamente registrados

) na fração (

no significando

).

A precisão (

quantidade de dígitos decimais usados no número decimal

) obtida com um número real de precisão

simples representado internamente segundo este padrão (

padrão IEEE 754-1985

) é de:

log

10

(2

24

) =7.22472 ≈ 7 dígitos (

porque o número de bits só pode ser inteiro

)

Cálculo de um número dada a sua representação interna

A figura 01 mostra como o número real de precisão simples +0.15625 é guardado dentro de um computador de

32 bits. O cálculo do valor guardado com esta representação utiliza a seguinte fórmula:

N

=−

1

s

×

1

f

×

2

e−127

onde:

s

= sinal

f

= significando (

significand

)

e

= expoente

Então o número:

0011110001000000000000000000000

tem:

s = 0 em decimal: s = 0

e = 0111100 e = 124

f = 01000000000000000000000 f = 0.25

logo

N

=−

1

0

×

1

0.25

×

2

124−127

=

1.25

×

2

−3

=

0.15625

Usando-se números reais de precisão simples pode-se representar números decimais na faixa:

1.18

×

10

38

(14)

Por sua vez, a representação interna dos números do tipo

real de precisão dupla

com sinal é feita assim:

Figura 02

– Representação interna do número real precisão dupla

Figura obtida de: http://en.wikipedia.org/wiki/Double_precision_floating-point_format (acessado em 10/04/2010)

O mesmo tipo de regra continua valendo, então:

sinal:

1 bit

expoente:

11 bits

significando: 53 bits (

52 explicitamente guardados

)

Com isto, o número real tem uma precisão de 15 dígitos (log

10

(2

53

) =15.954590 ≈ 15 )

Usando-se números reais de precisão dupla pode-se representar números decimais na faixa:

2.225

×

10

308

a

1.79769

×

10

308

Para calcular um número real de precisão dupla usa-se a fórmula:

N

=−

1

s

×

1

f

×

2

e−1023

No Fortran

No Fortran, a forma recomendada para definir números inteiros e números reais de precisão dupla é utilizando

as funções intrínsecas:

selected_int_kind

e

selected_real_kind

.

Função intrínseca selected_int_kind

A função intrínseca selected_int_kind retorna um valor inteiro (

que para a maioria dos compiladores

) representa a

quantidade de octetos (

bytes

) que o computador utiliza para guardar os números inteiros desejado.

Exemplos:

selected_int_kind(2)

Quantidade de octetos (

bytes

) usados para guardar um número inteiro que

esteja entre

10

2

e 10

2

a função retorna o inteiro

1

porque 1 octeto (

byte

) pode guardar

2

8

=

256

números na faixa -128 e

+127, que (

claramente

) abrange a faixa desejada -100 e +100

selected_int_kind(4)

Faixa

10

4

e 10

4

retorna o inteiro

2

2 octetos (

bytes

) →

2

16

=

65536

ou seja: -32768 a +32767 que responde

pela faixa desejada -10000 a +10000

selected_int_kind(9)

Faixa

10

9

e 10

9

(15)

selected_int_kind(16)

retorna o inteiro

8

8 octetos (

bytes

)→ 64 bits →

precisão dupla

[

para as máquinas que utilizam palavra de 32 bits

]

Para definir um inteiro de precisão dupla é necessário usar o especificador de parâmetro de tipo KIND.

program inteiro_simples_dupla

!--- !Exemplo de inteiro com precisão simples e precisão dupla ! Arquivo: inteiro_simples_dupla.f03

! AUTOR: Anibal L. Pereira 17/02/2011

!--- implicit none

integer:: i_simples = 364789776

integer( kind = selected_int_kind(16) ):: i_dupla = 364789776 print*

print"(a)"," ====================================================================" print"(2a)"," Multiplicação dos inteiros: ","3456 x 364789776 = 1260713465856" print"(a)"," ====================================================================" print*

print"(a,i13)","resultado usando precisão simples:", 3456*i_simples print"(a,i13)","resultado usando precisão dupla :", 3456*i_dupla print*

end program inteiro_simples_dupla

Execute este programa para ver como um programa simples, escrito sem cuidado, dá respostas

erradas !

Função intrínseca selected_real_kind

A função intrínseca selected_real_kind retorna um valor inteiro (

que para a maioria dos compiladores

) representa a

quantidade de bytes que o computador utiliza para guardar os números reais desejado.

Por exemplo:

real( kind = selected_real_kind(10) ):: x_duplo

declara a variável real

x_duplo

que tem no mínimo 10 dígitos decimais de precisão e faixa de expoente não

especificada.

real( kind = selected_real_kind(8,70) ):: x_duplo

declara a variável real

x_duplo

que tem no mínimo 8 dígitos decimais de precisão e faixa de expoente que inclui

valores entre

10

−70

e

10

70

em magnitude.

program real_simples_dupla

!--- !Exemplo de real com precisão simples e precisão dupla ! Arquivo: real_simples_dupla.f03

! AUTOR: Anibal L. Pereira 17/02/2011

!--- implicit none

real:: x_simples = 364789776.0E20

real( kind = selected_real_kind(16) ):: x_dupla = 364789776.06E20 print*

print"(a)"," ======================================================================" print"(2a)"," Multiplicação dos reais: ","3456.0E34 X 364789776.06E20 = 0.12607E+67" print"(a)"," ======================================================================" print*

(16)

print*

end program real_simples_dupla

Execute o programa e veja sua saída !

Forma mais recomendada

Definir uma constante com nome para receber o inteiro que especifica o número de octetos (

bytes

) a ser usado

na especificação de parâmetro de tipo é a forma mais adequada de proceder.

Ao se colocar num módulo as seguintes definições, estamos procedendo da forma mais adequada:

!--- Inteiro com 1, 2, 4 ou 8 bytes: ---integer,parameter:: I1B = selected_int_kind(2) ! inteiro 1 byte

integer,parameter:: I2B = selected_int_kind(4) ! inteiro 2 bytes

integer,parameter:: I4B = selected_int_kind(9) ! inteiro 4 bytes - precisão simples integer,parameter:: I8B = selected_int_kind(16) ! inteiro 8 bytes - precisão dupla !

!--- Real precisão simples, dupla e quádrupla ---integer,parameter:: sp = selected_real_kind(6,30) ! real precisão simples

integer,parameter:: dp = selected_real_kind(10,200) ! real precisão dupla integer,parameter:: qp = selected_real_kind(18,200) ! real precisão quádrupla

Parâmetro de tipo para constantes literais

O parâmetro de tipo (KIND) de uma constante numérica literal pode ser mudado pelo uso de um sufixo.

Escreva imediatamente à constante literal uma sublinha (

_

em inglês: underscore

) seguida da constante com

nome que define o parâmetro de tipo desejado.

Então, se

integer, parameter:: i8b = selected_int_kind(16)

define a constante com nome que contém o

valor de definição dos inteiros de precisão dupla, procede-se como mostrado no exemplo:

program literal_simples_duplo

!--- !Mostra uso de constante literal numérica inteira de precisão simples e precisão dupla ! Arquivo: literal_simples_duplo.f03

! AUTOR: Anibal L. Pereira 17/02/2011

!--- implicit none

integer, parameter:: i8b = selected_int_kind(16)

integer :: N = 2000000000 !valor máximo é 2147483647 print*

print*,"=============================================================================" print*,"Diferença obtida na multiplicando 6 x 2000000000 com precisão simples e dupla" print*,"=============================================================================" print*

print"(a, i20,a)"," 6 x 2000000000 = ", 6 * N, " <== valor errado!!!!" print"(a, i20)","6_i8b x 2000000000 = ", 6_i8b * N

print*

end program literal_simples_duplo

(17)

As informações colocadas aqui são bastante resumidas, mas muito importantes, portanto

leia com atenção.

Conforme destacado anteriormente, aprender a programar envolve duas tarefas distintas e simultâneas:

1. linguagem de programação

Fortran 2003

2. planejamento

análise e projeto

Apesar de serem tarefas distintas, geralmente realizadas por pessoas distintas, no nosso caso, elas são realizadas

por uma única pessoa. Por este motivo

é muito importante ter clareza e delimitar corretamente cada uma

destas tarefas

.

Aproximação ponha-para-funcionar

Esta aproximação possibilita enfatizar as regras de sintaxe e a utilização das estruturas da linguagem.

A aproximação

ponha-para-funcionar

é bastante eficiente para

evidenciar e exemplificar um conceito, uma informação, uma regra,

uma implementação.

Boa para aprender uma linguagem de programação.

Serve de suporte ao item 1 – linguagem de programação

Muito utilizada nos primórdios da computação, entretanto quando utilizada para escrever programas apresenta

deficiências sérias

Aproximação codifica-conserta

Aproximação

codifica-conserta

(

Code-Fix Approach

) é uma

melhora na aproximação ponha-para-funcionar.

é a mesma aproximação ponha-para-funcionar com a

diferença de possibilitar a especificação de mais de

um propósito ou requisito (especificação do

sistema)

Nesta aproximação, inicialmente faz-se a especificação do que se deseja (

determinação dos requisitos do sistema

)

para então iniciar a codificação e realizar (

executar

) vários ciclos da aproximação codifica-conserta. De tempo em

tempo, verifica-se se o programa atende as especificações desejadas. Quando atender, o programa está pronto.

(18)

Modelo em Cascata

Um passo importante na evolução da técnica de

desenvolvimento de software foi a criação do

modelo em cascata.

O

modelo em cascata

é um modelo sequencial no

qual o desenvolvimento do software (

sistema

) é um

fluir constante para a frente através de fases:

conceito, análise de requisitos, projeto,

implementação e teste (

validação

).

No modelo em cascata, mover-se de uma fase à

outra somente depois da fase anterior estar

completa e perfeita. Não há pulo para a frente, para

trás ou sobreposição entre as fases.

O modelo em cascata permite que o

trabalho com sistema de alta complexidade

, que possuem muitos

requisitos para serem satisfeitos. O modelo em cascata responde muito bem pelo item 2 – planejamento.

A grande dificuldade da utilização do método em cascata advêm do fato dele não permitir que se passe de uma

fase à outra sem que a fase anterior esteja completa e correta. Por isto, ele é pouco flexível o que cria dificuldades

para a sua utilização.

Desenvolvimento Rápido de Aplicação

O passo seguinte ao método em cascata foi a criação do

Desenvolvimento Rápido de Aplicação

(Rapid

Application Development

– RAD)

. O desenvolvimento rápido de aplicação é um modelo de desenvolvimento de

software iterativo e incremental que enfatiza um ciclo de desenvolvimento extremamente curto.

I

terativo e Incremental

desenvolvimento iterativo e incremental

(

IID

iterative and incremental development

) foi um processo

criado para lidar com as fraquezas do modelo em cascata. Neste desenvolvimento, inicia-se com um

plano inicial (planejamento) e segue-se com vários ciclos incrementais (

evolutivos

) até terminar com o

produto final.

É muito importante lembrar que o desenvolvimento rápido de aplicativo (RAD) é um processo

iterativo e incremental (IID)

O desenvolvimento rápido de aplicação (RAD) usa planejamento mínimo em favor de rápida prototipagem.

No desenvolvimento rápido de aplicação (RAD) o planejamento é sempre

intercalado com o processo de escrever o software

O desenvolvimento rápido de aplicação foi uma tentativa de encontrar a solução da questão: “

Como se pode

construir sistemas rapidamente, mantendo-se o controle sobre o produto?”.

(19)

As informações que seguem ajudarão à uma melhor compreensão do processo:

diálogo usuário-desenvolvedor

fundamentalmente, desenvolver um software é estabelecer um diálogo entre o cliente

(

cliente = customer

) e o desenvolvedor

Cliente Desenvolvedor

Eu tenho uma ideia.

Boa ideia, o que você deseja?

O que desejo é …

Entendi, se eu construir isto, ele

atende suas necessidades?

Sim, pode fazer.

Pronto, terminei. Está bom?

Sim, perfeito!

cliente e desenvolvedor

(20)

neste texto, o termo

usuário

será utilizado tanto quanto o termo

cliente

Desenvolvedor (

muita vezes um time composto por analistas e programadores

) é o responsável pelo

desenvolvimento do software

usuário e desenvolvedor são “entidades” distintas que devem ser considerado quando se desenvolve

um software

dois em um

para o desenvolvimento de software de porte pequeno (

caso dos programas feitos em nossa disciplina

) o

usuário (

cliente

) e o desenvolvedor serão a mesma pessoa. Esta única pessoa passa então a ser

responsável tanto pela definição dos requisitos (

estabelecido pelo cliente quando diz o que deseja ou espera do software

) quanto pelo trabalho (

desenvolvimento do software

)

Então, o processo de desenvolvimento rápido de aplicação (RAD)

que é assim:

(21)

Fica assim:

entendimento claro dos requisitos

é importante ter noção que o método de desenvolvimento rápido de aplicação (RAD) só funciona

corretamente se o desenvolvedor entender com clareza o que o cliente quer, isto é, se o desenvolvedor

entende, sem margem de dúvida, os requisitos desejados. Falha ou incerteza no entendimento dos

requerimentos quebrar o desenvolvimento do software

dois problemas

quando uma única pessoa (

dois em um

) é responsável por definir os requisitos e desenvolver o software

(

faz o papel de cliente e de desenvolvedor

), ainda assim o processo de desenvolvimento rápido de

aplicação (RAD) pode sofrer por causa do:

(1) mal entendido do problema a ser resolvido, o que leva ao estabelecimento de requisitos errados ou

incompletos e

(2) (

caso mais comum

) os requisitos são alterados durante a fase de desenvolvimento, fazendo com que

os códigos escritos acabem como um ajuntamento de códigos sem coerência –

caótico

. Neste caso, o

desenvolvimento acaba se transformando na aproximação codifica-conserta

Aproximação Protótipo-Evolutivo

Em nossa disciplina, os programas serão desenvolvidos utilizando a aproximação

protótipo evolutivo

(Evolutionary prototyping –

EP

). Esta aproximação será utilizada porque ela é bastante adequada para nossos

propósitos.

(22)

Baseado no planejamento (análise), escreve-se um protótipo, onde os requisitos (pelo menos os

principais) são implementados sem muitos detalhes. Coloca-se o protótipo para funcionar. Faz-se

um primeiro teste (o protótipo responde pelo que se deseja?). Após o teste (avaliação realizada

depois de uma iteração), refina-se os requisitos (ajusta-se e/ou acrescenta-se novos).

Modifica-se o protótipo para responder aos novos e/ou requisitos ajustados (nova iteração). Novo teste.

Novo refinamento! Nova iteração . . . . . . Depois de N iterações o programa vai ganhando

consistência (e geralmente aumentando de tamanho) até que não mais serão necessárias

redefinições ou ajustes. Quando isto ocorrer, finaliza-se o programa!

A aproximação protótipo-evolutivo (EP) é bastante flexível. Ela iterativamente produz evoluções do sistema até

alcançar o produto final. Em cada iteração, as modificações necessárias são implementadas e quando necessário

novas funcionalidades são adicionadas.

Apesar da aproximação protótipo-evolutivo ser adequada para lidar com mudanças e acréscimo de requisitos,

durante uma iteração os requisitos não mudam. Ao final da iteração os requisitos são avaliados e, se

necessário, ajustes e acréscimos são identificados e registrados para serem implementados na nova iteração

.

A aproximação protótipo-evolutivo (EP) é uma boa abordagem, garantido que o processo todo não se reduza à

ciclos de codifica-conserta.

A grande dificuldade é exatamente esta, garantir que este tipo de redução não ocorra

.

Como não reduzir a aproximação protótipo-evolutivo à aproximação codifica-conserta:

Só codifique para implementar requisitos previamente definidos (planejados).

Redefinição e até mesmo acréscimo de requisito podem acontecer a qualquer momento, mas tem

que obrigatoriamente ser registrados para que possam ser submetida a testes (avaliação). Se

mudanças significativas nos requisitos acontecerem, isto obriga que seja feita uma reavaliação do

planejamento, porque a lógica utilizada não está respondendo adequadamente ao problema.

(23)

fáceis de serem trabalhados. Quando tudo vai bem, a baixa complexidade do sistema, permite que o protótipo

(

solução inicial

) seja muito próximo da solução final e uma ou umas poucas iterações acabam levando ao produto

final desejado.

8. Nossa implementação

Para realizar a aproximação protótipo-evolutivo, faz-se o seguinte:

1. definir requisitos

planejamento

– especifica-se com clareza a tarefa e analisar o problema para quebrá-lo em

elementos fundamentais que facilitarão a solução

2. codificar

protótipo

– (

escrever o protótipo

) de acordo com o passo 1

3. testar

validação

– testar o protótipo e (quando necessário) redefinir o planejamento.

4. Repetir os passos 1, 2 e 3

iteração

– repetir tantas vezes quanto necessárias, até que o protótipo funcione corretamente em

todas as situações

Pode-se dizer que escrever um programa significa essencialmente:

(1) Planejamento (definir a tarefa, análise e solução) e (2) Codificação.

Em nossa disciplina, o planejamento é feito e documentado utilizando-se a

documentação externa

da atividade

(

ver item 6.3

). O seguinte entendimento pode ser feito:

Definir a Tarefa

5) Propósitos:

Análise e Solução

8) Método:

9) Comentários e Observações:

Algoritmo

10) Pseudocódigo(s) ou Fluxograma(s) ou Diagrama(s) NS

A relação não é restritiva, isto é, os itens não são estanques, eles podem se sobrepor em algum grau.

9. Documentação Externa

A documentação externa de um programa é onde se faz o planejamento da atividade e também como

disponibilizamos as informações mais importantes de uma atividade (

tarefa, problema ou programa

).

Porque a documentação externa é uma fonte de informação separada do código fonte, ela, frequentemente, é

perdida, o que é péssimo. A documentação externa é muito importante (porque é o planejamento; é o local onde

resolvemos o problema ou tarefa) e deve ser tratada com bastante cuidado.

Em nossa disciplina a

documentação externa

deve ser preparada seguindo as seguintes regras:

Capa

todo trabalho entregue tem que ter uma capa (

é obrigatório a existência da capa

)

ela é feita em folha de papel A4 sem pauta e visa identificar o trabalho

ela contém: identificação da instituição, instituto, departamento, disciplina, turma, nome do aluno, ano e

semestre

(24)

Universidade do Estado do Rio de Janeiro Instituto de Física Armando Dias Tavares

Departamento de Física Aplicada e Termodinâmica Física Computacional A

Atividade 02

Conceitos Iniciais

Turma 03

Anibal Leonardo Pereira

2009 segundo semestre

Figura 04

– Exemplo de capa para a documentação externa

Corpo da documentação externa

Escrito em folhas papel A4, sem pauta e contém os seguintes itens:

1) Atividade

identifica a atividade que está sendo documentada

2) Autor

identifica autor e data

3) Programa(s)

nome ou nomes dos programas

4) Arquivo(s)

nome ou nomes dos arquivos que compõem a atividade

5) Propósito(s)

identifica o fim ou os fins a serem alcançados pela atividade

6) Identificação dos Dados

identifica as variáveis tanto de entrada quanto de saída

7) Subprogramas

lista os subprogramas utilizados (módulos, funções e sub-rotinas)

8) Método

descreve e identifica o problema e (principalmente) o método ou técnica utilizada para resolver o problema

9) Comentários e Observações

quando necessários

10) Pseudocódigo(s) ou Fluxograma(s) ou Diagrama(s) NS

(25)

Um exemplo de

documentação externa

é mostrada na sequência. Para uma melhor visualização considere

a borda preta em volta como sendo os limites de uma folha A4, sem pauta.

1) Atividade: f02a5 pg. 01 2) Autor: Anibal L. Pereira 03/01/2009

3) Programa(s): minimo_1

4) Arquivo(s): f02a5.f03

5) Propósito(s): Escrever na tela do micro “Programa minimo 1 !”

6) Identificação dos Dados:

Entrada(s): nenhuma

Saída(s): constante do tipo caractere

7) Subprogramas:

[módulos] nenhum

[funções] nenhuma

[sub-rotinas] nenhuma

8) Método:

A tarefa (propósito) deste programa é realizada utilizando-se a declaração print do Fortran

9) Comentários e Observações:

O programa é bastante simples. Essencialmente ele utiliza a declaração print do Fortran e possuí diversos comentários que fazem a documentação interna do programa

10) Pseudocódigo(s) ou Fluxograma(s) ou Diagrama(s) NS:

algoritmo {programa minimo_1} {cabeçalho do programa}

escreva " Programa minimo 1 ! " fim algoritmo

O programa

minimo_1

da atividade 05, salvo no arquivo f02a5.f03, é mostrado a seguir.

program minimo_1 !

!---! Propósito: Programa fonte (Fortran 2003) que escreve um texto na tela do ! micro utilizando a declaração print

!---! Arquivo: f02a5.f03

! Autor: Anibal L. Pereira 08/01/2009 !Revisões:

!---implicit none

print*

print*,"Programa Minimo 1 !" print*

end program minimo_1

(26)

Esta Folha contém

13 Atividades

12 atividades exemplos

01 atividade exemplo com ajustes e/ou acréscimos

00 atividades para serem feitas

00 atividades para serem ajustadas e/ou acrescidas

Seu professor de laboratório (e/ou teoria) poderá alterar esta relação !

Código da folha de atividades

Acesse a Home Page da disciplina, entre no link Datas-e-Atividades, para obter o código da

folha de atividades. Toda atividade tem que ter o "xx" substituído pelo código indicado. Exemplos: código 02 ► fxxa3.f03

f02a3.f03

Atividade 01

Entregar em meio magnético:

1. programa: contagem_regressiva fxxa1.f03

2. Documentação externa: PARTE Entregar em papel o fluxograma do programa

Exemplo:

Exemplifica uso de número aleatório

Faz contagem regressiva iniciando com número entre 0 e 9 na tela do micro Uso da estrutura de repetição com número de repetição definida

O pseudocódigo do programa é mostrado a seguir:

algoritmo

declare i, {contador} na, {número inicial}

num_a {número aleatório} numérico aleatório(num_a)

na

10 * num_a

escreva " Iniciando a contagem regressiva !" para i de na até 0 passo -1 faça

escreva i fim para fim algoritmo

FAZER:

Escreva o fluxograma do programa. Entregar (em papel) o fluxograma (não esqueça que o trabalho tem que ser entregue com uma capa)

Escreva o programa

contagem_regressiva

e salve-o no arquivo

fxxa1.f03

Não deixe de atualizar o cabeçalho de forma adequada.

(27)

arquivo: fxxa1.f03

◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄

¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

program contagem_regressiva !

!--- ! Propósito: Faz uma contagem regressiva na tela do micro

! iniciando em um número qualquer entre 10 e 1

!--- ! Arquivo: fxxa1.f03

! Autor: Anibal L. Pereira 02/10/2002 !Revisões: Anibal L. Pereira 28/09/2006 ! Anibal L. Pereira 17/02/2011 !

!--- implicit none

integer:: i, & ! contador do loop na ! número inicial real:: num_a ! número aleatório call random_number(num_a)

na=10*num_a

print*, " Iniciando a contagem regressiva !" !---

! imprime a contagem regressiva

!--- do i=na,0, -1

print"(t10,i2)", i end do

end program contagem_regressiva

Atividade 02

Entregar em meio magnético:

1. programa: contagem_regressiva_par fxxa2.f03

2. Documentação externa: PARTE Entregar em papel o fluxograma do programa

Exemplo:

Faz uma contagem regressiva pulando números impares Uso da estrutura de repetição com número de repetição definida

Observe que em cada execução do programa a contagem é sempre igual Para pular uma repetição usa-se a declaração cycle

if(condicao) cycle

Pseudocódigo do programa:

algoritmo

declare i, {contador} na, {número inicial}

num_a {número aleatório} numérico aleatório(num_a)

na

10 * num_a

escreva " Iniciando a contagem regressiva !" para i de na até 0 passo -1 faça

se(modulo(i,2)≠ 0) pul a {pula} escreva i

Imagem

Figura 01 – Representação interna do número real precisão simples +0.15625
Figura 02 – Representação interna do número real precisão dupla
Figura 04 – Exemplo de capa para a documentação externa

Referências

Documentos relacionados

- Se tiver quaisquer efeitos secundários, incluindo possíveis efeitos secundários não indicados neste folheto, fale com o seu médico ou farmacêutico.. Atarax 2 mg/ml xarope

Em graduações em licenciatura, tende-se a sonhar com uma sala de aula ideal, em que tudo funciona de maneira ideal, no belo e fantasioso quadro pintado por muitos

Fale com o seu médico, com o médico que trata a sua criança ou farmacêutico antes de tomar Latanoprost Aurovitas ou antes de aplicar este medicamento à sua criança, se pensa

Constituído como uma entidade sem fins lucrativos, o InternetLab atua como ponto de articulação entre acadêmicos e representantes dos setores público, privado e da sociedade

medicamentos tais como Junifen 60 mg supositórios podem estar associados a um pequeno aumento do risco de ataque cardíaco (enfarte do miocárdio) ou Acidente Vascular Cerebral

E) CRIE NO SEU CADERNO UM TÍTULO PARA ESSA HISTÓRIA EM QUADRINHOS.. 3- QUE TAL JUNTAR AS SÍLABAS ABAIXO PARA FORMAR O NOME DE CINCO SUGESTÕES DE PRESENTE PARA O DIA

- for idoso, pois a sua dose de Zonisamida Pentafarma pode precisar de ser ajustada e pode ter uma maior probabilidade de vir a desenvolver uma reação alérgica, uma erupção

- Se desenvolver uma erupção na pele ou estes sintomas da pele, pare de tomar Meloxicam Sandoz, procure conselho médico urgente e diga que está a tomar este medicamento.. Crianças