MAC2166 - Introdução à Computação

19/05/2014 - Aula 14

Representação de Números Reais

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.

Problemas em Operações Envolvendo Valores do Tipo 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:

Para saber mais sobre esse assunto...

... leia as seguintes referências: * Ponto flutuante, na Wikipédia -- http://pt.wikipedia.org/wiki/Ponto_flutuante * Error propagation - http://floating-point-gui.de/errors/propagation/ * Floating Point Arithmetic: Issues and Limitations -- https://docs.python.org/3/tutorial/floatingpoint.html

Problema 30

Dado um número inteiro n > 0, determinar o número harmônico Hn dado por

Hn = 1 + 1/2 + 1/3 + 1/4 + . . . + 1/n .

Imprima cada termo da sequência e o resultado final.

Você pode implementar da direita para a esquerda e da esquerda para direita. Qual dessas formas é estável?

Obs.: Este problema corresponde ao exercício 2 da lista de exercícios sobre reais.

In [3]:
n = int(input("Digite n: "))

# Solução 1: calcula a soma da esquerda para a direita
H_0aN = 0
for x in range (1, n+1):
    H_0aN += 1 / x
#    print ("Termo %d: 1 / %d = %.10f   H(%d) = %.10f"%(x, x, 1/x, x, H_0aN))

# Solução 2: calcula a soma da direita para a esquerda
H_Na0 = 0
for x in range(n, 0, -1):
    H_Na0 += 1 / x
#    print ("Termo %d: 1 / %d = %.10f   H(%d) = %.10f"%(x, x, 1/x, x, H_Na0))

print("De 0 a N temos: %.30f\nDe N a 0 temos: %.30f"%(H_0aN, H_Na0))
print("Esses valores são iguais? ", H_0aN == H_Na0)
Digite n: 100
De 0 a N temos: 5.187377517639620627676322328625
De N a 0 temos: 5.187377517639621515854742028750
Esses valores são iguais?  False

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.

Obs2.: A soma calculada dos menores termos para os maiores (H_Na0) é a solução mais estável, por envolver operações de soma entre números de valores mais próximos um do outro.

Problema 31

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 + x**2/2! + x**3/3! + . . . + x**k/k! + . . .

Inclua na aproximação todos os termos até o primeiro de valor absoluto (módulo) menor do que epsilon.

In [6]:
SOL2 = True  # Quando essa constante vale True, o programa 
             # exibe o resultado calculado pela Solução 2

x   = float(input("Digite x: "))
eps = float(input("Digite epsilon: "))

termo = 1
soma  = 1
k = 0

# Solução 1
while termo >= eps or -termo >= eps:
    k += 1
    termo = x * termo / k
    soma += termo
#    print (termo, soma)

print ("e**(%5.3f) = %7.4f"%(x, soma))

# Solução 2: usando o operador de exponenciação
if SOL2:
    termo = 1
    soma = 1
    k = 0
    fat = 1
    while termo >= eps or -termo >= eps:
        k+=1
        fat *= k
        termo = x**k / fat
        soma += termo
#        print (termo, soma)
    print ("Solução 2: e**(%5.3f) = %7.4f"%(x, soma))
Digite x: 25.3456
Digite epsilon: 0.00001
e**(25.346) = 101731212450.5873
Solução 2: e**(25.346) = 101731212450.5873

Problema 32

Dados números reais x ≥ 0 e epsilon > 0, calcular uma aproximação da raiz quadrada de x através da seguinte sequência: r0 = x e rn+1 = 1/2 (rn + x/rn).

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 rn+1 tal que |rn+1-rn| < epsilon.

In [7]:
DEBUG = False

x   = float(input("Raiz de x +/- eps ==> digite x >= 0: "))
eps = float(input("Raiz de x +/- eps ==> digite eps > 0: "))

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
    if DEBUG:
        print (x, eps, Ratual, Rant, dif)

print ("A raiz de %f = %f (com precisão %f)"%(x, Ratual, eps))
Raiz de x +/- eps ==> digite x >= 0: 49.6729
Raiz de x +/- eps ==> digite eps > 0: 0.00001
A raiz de 49.672900 = 7.047900 (com precisão 0.000010)

Problema Extra

Dados números reais a, b e c, calcular as raízes da equação ax2 + bx + c = 0, usando a função sqrt() do módulo math. Imprimir a solução em uma das seguintes formas:

    DUPLA     REAIS DISTINTAS                COMPLEXAS
    raiz      raiz 1                         parte real
              raiz 2                         parte imaginária
              
              

Obs.: Este problema corresponde ao exercício 5 da lista de exercícios sobre reais.

In [12]:
import math

print("\n\tCalculo das raizes da equacao ax^2+bx+c=0\n")
a = float(input("Digite o numero a: "))
b = float(input("Digite o numero b: "))
c = float(input("Digite o numero c: "))

# calculo do delta da equacao 
delta = b*b - 4*a*c;

if delta > 0:
  # a equacao tem raizes reais 
  rdelta = math.sqrt(delta)
  raiz1 = (-b+rdelta)/(2*a)
  raiz2 = (-b-rdelta)/(2*a)
  print("Raizes reais")
  print("Raiz 1: %f" %raiz1)
  print("Raiz 2: %f" %raiz2)
    
elif delta < 0:
  # a equacao tem raizes complexas
  rdelta = math.sqrt(-delta)
  parte_real = -b/(2*a)
  parte_imaginaria = rdelta/(2*a)
  print("Raizes complexas")
  print("Parte real: %f" %parte_real)
  print("Parte imaginaria: %f" %parte_imaginaria)

else:
  # a equacao tem raiz dupla
  print("Raiz dupla: %f" %(-b/(2*a)))

	Calculo das raizes da equacao ax^2+bx+c=0

Digite o numero a: 1
Digite o numero b: -4
Digite o numero c: 5
Raizes complexas
Parte real: 2.000000
Parte imaginaria: 1.000000

Tópicos vistos na Aula 14

Referências e outros materiais para estudo