Número reais são representados na memória do computador de forma análoga à notação científica, feita em ponto fluante, como mostrado a seguir:
$$0.x_1x_2x_3...x_k \times B^e$$
onde $x_1x_2x_3...x_k$ é a mantissa (os $k$ dígitos mais significativos do número), $B$ é a base e $e$ é o expoente (que determina a posição correta do dígito mais significativo do número em ponto flutuante).
Exemplos de números reais representados em ponto flutuante:
Número | Notação Científica | Mantissa | Base | Expoente |
---|---|---|---|---|
$1000000000$ | $0.1 \times 10^{10}$ ou $1$E$9$ | $1$ | $10$ | $10$ |
$123000$ | $0.123 \times 10^{6}$ ou $1.23$E$5$ | $123$ | $10$ | $6$ |
$456.78$ | $0.45678 \times 10^{3}$ ou $4.5678$E$2$ | $45678$ | $10$ | $3$ |
$0.00123$ | $0.123 \times 10^{-2}$ ou $1.23$E$-3$ | $123$ | $10$ | $-2$ |
Observe que os valores para a mantissa e o expoente são números inteiros. Portanto, se temos uma certa quantidade fixa de bits para armazenar um número real, podemos usar boa parte dessa quantidade para armazenar a mantissa e uma parte menor para armazenar o expoente. E com isso conseguimos representar uma quantidade bem grande de valores reais distintos. Entretanto, de modo análogo ao que acontece com os números inteiros, com uma quantidade fixa de bits conseguimos representar uma quantidade limitada de valores reais, ou, em outras palavras, números reais com precisão limitada). E como o computador é uma máquina com capacidade de armazenamento finita, ele é capaz de representar apenas um subconjunto do conjunto (infinito!) de números reais da matemática.
Obs.: O conteúdo desta seção foi extraído do Capítulo 13 - Números Reais - Tipo float, da apostila Introdução a Ciência da Computação em C.
float
A página sobre propagação de erros traz dicas importantes relacionadas aos cuidados que é preciso ter na implementação de cálculos envolvendo números reais representados em ponto flutuante:
... leia as seguintes referências:
Dado um número inteiro $n > 0$, determinar o número harmônico $H_n$ dado por
$$H_n = 1 + \frac{1}{2} + \frac{1}{3} + \frac{1}{4} + ... + \frac{1}{n} $$
Você pode implementar a soma da direita para a esquerda ou da esquerda para direita. Qual dessas formas é estável?
Obs.: Este problema corresponde ao exercício 2 da lista de exercícios sobre reais.
def harmonico1(n):
# Solução 1: calcula a soma da esquerda para a direita
H = 0
for x in range (1, n+1):
H += 1 / x
#print ("Termo %d: 1 / %d = %.10f H(%d) = %.10f"%(x, x, 1/x, x, H)) # só para vermos os termos calculados
return H
def harmonico2(n):
# Solução 2: calcula a soma da direita para a esquerda
H = 0
for x in range(n, 0, -1):
H += 1 / x
#print ("Termo %d: 1 / %d = %.10f H(%d) = %.10f"%(x, x, 1/x, x, H)) # só para vermos os termos calculados
return H
def main():
n = int(input("Digite n: "))
H_0aN = harmonico1(n) # soma calculada da esquerda para a direita
H_Na0 = harmonico2(n) # soma calculada da direita para a esquerda
print("De 0 a N temos: %.30f" %H_0aN)
print("De N a 0 temos: %.30f" %H_Na0)
print("Esses valores são iguais? ", H_0aN == H_Na0)
####################
main()
Obs1.: Aos testar o programa para valores pequenos de n, os valores calculados para Hn "da esquerda para direita" e "da direita para esquerda" são equivalentes. Mas para valores de n
maiores, os resultados calculados pelas duas estratégias se diferem. Como exemplo, compare os resultados do programa para n=10
e depois para n=100
Obs2.: A soma calculada dos menores termos para os maiores (função harmonica2
) é a solução mais estável, por envolver operações de soma entre números de valores mais próximos um do outro.
Dado um número real $x$ e um número real $epsilon > 0$, calcular uma aproximação de $e^x$ através da seguinte série infinita:
$$e^x = 1 + x + \frac{x^2}{2!} + \frac{x^3}{3!} + ... + \frac{x^k}{k!} + . . .$$
Inclua na aproximação todos os termos até o primeiro de valor absoluto (módulo) menor do que $epsilon$.
def exponencial1(x,eps):
# solução 1: os termos são calculados como aparecem na fórmula
termo = 1
soma = 1
k = 0
fat = 1
while termo >= eps or -termo >= eps:
k += 1
fat *= k
termo = x**k / fat
soma += termo
return soma
def exponencial2(x,eps):
# solução 2: mais eficiente pois realiza menos operações
# (já que não precisa calcular a exponenciação x**k a cada execução do laço)
termo = 1
soma = 1
k = 0
while termo >= eps or -termo >= eps: # equivale a: while abs(termo) >= eps
k += 1
termo = x * termo / k
soma += termo
return soma
def main():
x = float(input("Digite x: "))
eps = float(input("Digite epsilon: "))
# Solução 1: usando o operador de exponenciação
print("e**(%5.3f) = %7.4f" %(x, exponencial1(x,eps)))
# Solução 2: sem usar o operador de exponenciação
print ("e**(%5.3f) = %7.4f" %(x, exponencial2(x,eps)))
################
main()
Dados números reais $x \leq 0$ e $epsilon > 0$, calcular uma aproximação da raiz quadrada de $x$ através da seguinte sequência: $$\begin{array}{l c l} r_0 & = & x \\ r_{n+1} & = & \left( r_n + \frac{x}{r_n}\right) /2 \end{array}$$
Exemplos:
Para x = 3, r0 = 3, r1 = 2, r2 = 1.75, r3 = 1.732143, r4 = 1.732051
Para x = 4, r0 = 4, r1 = 2.5, r2 = 2.05, r3 = 2.000610, r4 = 2.000000
Para x = 5, r0 = 5, r1 = 3, r2 = 2.33, r3 = 2.238095, r4 = 2.236068
Para x = 0.81, r0 = 0.81, r1 = 0.905, r2 = 0.9000138122, r3 = 0.9000000001
A aproximação será o primeiro valor $r_{n+1}$ tal que $|r_{n+1}-r_n| < epsilon$.
def raiz_quadrada(x,eps):
Rant = x
Ratual = (Rant + 1.0) / 2.0
dif = Ratual - Rant
while dif >= eps or dif <= -eps:
Rant = Ratual
Ratual = (Ratual + x / Ratual) / 2.0
dif = Ratual - Rant
# print (x, eps, Ratual, Rant, dif) # descomente esta linha para imprimir o valor de cada ri
return Ratual
def main():
x = float(input("Raiz de x +/- eps ==> digite x >= 0: "))
eps = float(input("Raiz de x +/- eps ==> digite eps > 0: "))
print ("A raiz de %f = %f (com precisão %f)" %(x, raiz_quadrada(x,eps), eps))
########################
main()
Dados $x$ real e $n$ natural, calcular uma aproximação para $cos(x)$ através dos $n$ primeiros termos da seguinte série
$$ cos(x) = 1 − \frac{x^2}{2!} + \frac{x^4}{4!} − \frac{x^6}{6!} + ... + (−1)^k\frac{x^{2k}}{2k!} + ... $$
Compare com os resultados de sua calculadora!
def cosseno(x,n):
soma = t = 1.0
for k in range (1,n+1):
t = -1 * t * x*x / ((2*k - 1) * 2*k)
soma += t
return soma
def main():
x = float(input("Digite o valor de x: "))
n = int(input("Digite o valor de n: "))
print("O valor aproximado para cos(%f) é: %f" %(x, cosseno(x,n)))
##############
main()
Dados $x$ real e $epsilon$ real, $epsilon > 0$, calcular uma aproximação para $sen(x)$ através da seguinte série infinita:
$$ sen(x) = \frac{x}{1!} − \frac{x^3}{3!} + \frac{x^5}{5!} + ... + (−1)^k \frac{x^{2k+1}}{(2k+1)!} +... $$
incluindo todos os termos até que $\frac{|x^{2k+1}|}{(2k+1)!} < epsilon $.
Compare com os resultados de sua calculadora!