Agora já temos os componentes básicos da linguagem Python para poder atacar os problemas de física
no entanto, precisamos explorar ainda as limitações do computador visto que não pode guardar números com precisão infinita
existe um limite superior e inferior ao que se pode guardar e também de velocidade em que operações podem ser efetuadas
o maior numero float que pode ser armazenado é em módulo $10^{308}$
o mesmo vale para numeros imaginários
usualmente escrevemos os numeros de ponto flutuante grandes com notação científica na forma : 3.14e10 o que equivale a $3.14 \times 10^{10}$
caso uma operação gere um numero maior que o máximo aceito pelo computador o valor inf será alocado e em geral o programa não é interrompido.
In [1]:
x = 1.e308
y = x * 10.
print x,y
em Python inteiros podem ter tantos algarismos quanto a memória do computador permitir
In [6]:
factorial = 1
for k in range(1,201):
factorial *= k
print factorial
In [7]:
factorial = 1.0
for k in range(1,201):
factorial *= k
print factorial
números de ponto flutuante só podem ser representados com uma certa precisão
Em Python o padrão de representação é de 16 algarismos significativos
Veja o caso de $\pi$:
valor verdadeiro: 3.1415926535897932384626 . . .
valor no Python: 3.141592653589793
diferença: 0.0000000000000002384626 . . .
In [14]:
import numpy as np
import math as math
print np.pi
print math.pi
np.pi
Out[14]:
Uma lição importante é que floats não devem ser usados na avaliação de igualdades
veja abaixo:
In [2]:
x = 1.1+2.2
print "%10.20e"% x
if x == 3.3:
print "o valor é:", x
In [3]:
# a melhor maneira de testar igualdade de floats, caso seja necessária seria:
x = 1.1+2.2
epsilon = 1e-12
if abs(x-3.3)<epsilon:
print "o valor é:", x
As mesmas regras de propagação de erros são válidas no tratamento de erros no computador
pode-se mostrar que o erro de uma soma de N números é dada por:
$\sigma = C\sqrt{N}\sqrt{\bar{x}^2}$
Veja que o erro cresce com o numero de termos somados (para mais detalhes veja: http://www.umich.edu/~mejn/cp/chapters/errors.pdf)
De modo geral esse comportamento é razoável e o erro relativo tende a diminuir com o aumento de termos somados. Problemas em geral acontecem quando se somam números de tamanhos muito diferentes. Nesses casos os números muito menores podem se perder no erro.
Os maiores problemas acontecem quando fazemos subtração de numeros. Veja o exemplo abaixo:
In [6]:
# o caso abaixo mostra uma situação onde o erro relativo é bem grande
x = 1000000000000000
y = 1000000000000001.2345678901234
print "%10.20f"% x, '\n',"%10.20f"% y,'\n',"%10.20f"% (y-x)
print (1.2345678901234 - (y-x) ) / 1.2345678901234
In [36]:
# outro exemplo envolvendo subtração de numeros
from math import sqrt
x = 1.0
y = 1.0 + (1e-14)*sqrt(2)
print((1e14)*(y-x))
print(sqrt(2))
Veja que o erro cometido está na segunda casa decimal!
problemas de erros ao subtrair numeros muito próximos podem ocorrer em cálculos de física e devemos ficar atentos a eles
In [5]:
niter = 20
x = 0.2
for i in range(niter):
x = (11.0*x - 2.0)
print i, '->', "%10.20f"% x
é interessante ter uma noção sobre os limites de velocidade de computação
esses aspectos podem ser importantes na tomada de decisões de programação
O oscilador harmonico simples quantico tem niveis de energia dados por:
$E_n = \hbar \omega (n+\frac{1}{2})$
A energia média para o oscilador a uma temperatura T é:
$\left\langle E\right\rangle =\dfrac {1} {Z}\displaystyle\sum _{n=0}^{\infty }E_{n}e^{-\beta E_{n}}$
onde $\beta =1 / k_{B}T$ com $K_B$ a constante de Boltzmann e $Z=\displaystyle\sum _{n=0}^{\infty }e^{-\beta E_{n}}$
Suponha que se queira calcular o valor de $\left\langle E\right\rangle$ quando $k_{B}T = 100$
Usando unidades de $\hbar =\omega =1$ temos o programa abaixo:
In [40]:
from math import exp
import time
# para obter o tempo de execução
start_time = time.time()
# variáveis definidas no início para clareza
terms = 1000 # número de termos a serem usados na soma
beta = 1/100.
S = 0.0
Z = 0.0
# note o uso de um looping para calculo das duas somas e o exponencial calculado uma só vez
for n in range(terms):
E = n + 0.5
weight = exp(-beta*E)
S += weight*E
Z += weight
print(S/Z)
print("tempo de execução de %s secundos" % (time.time() - start_time))
In [42]:
from math import exp
import time
# para obter o tempo de execução
start_time = time.time()
# variáveis definidas no início para clareza
terms = 1000*1000 # número de termos a serem usados na soma
beta = 1/100.
S = 0.0
Z = 0.0
# note o uso de um looping para calculo das duas somas e o exponencial calculado uma só vez
for n in range(terms):
E = n + 0.5
weight = exp(-beta*E)
S += weight*E
Z += weight
print(S/Z)
print("tempo de execução de %s secundos" % (time.time() - start_time))
In [2]:
from math import exp
import time
# para obter o tempo de execução
start_time = time.time()
# variáveis definidas no início para clareza
terms = 100*1000*1000 # número de termos a serem usados na soma
beta = 1/100.
S = 0.0
Z = 0.0
# note o uso de um looping para calculo das duas somas e o exponencial calculado uma só vez
for n in range(terms):
E = n + 0.5
weight = exp(-beta*E)
S += weight*E
Z += weight
print(S/Z)
print("tempo de execução de %s secundos" % (time.time() - start_time))
In [ ]: