A precisão da máquina é definida como sendo o menor número positivo em aritmética de ponto flutuante
, tal que
. Este número, o menor número representável, depende totalmente do sistema de representação da máquina: base numérica, total de dígitos na mantissa, da forma como são realizadas as operações e do compilador utilizado. É importante conhecermos a precisão da máquina porque em vários algoritmos precisamos fornecer como dado de entrada um valor positivo, próximo de zero, para ser usado em testes de comparação com zero. Escreva um código em Fotran e em Python que tenha por objetivo estimar a precisão do computador e compilador que você está usando.
Passo 1
O que o enunciado pede e quais informações temos:
- Pede: escrever um código em Fortran e um em Python para estimar a precisão da máquina/compilador que está sendo usado.
- Informação-chave dada: a precisão da máquina é o menor número positivo
tal que em aritmética de ponto flutuante. - Resultado esperado: dois programas (Fortran e Python) que calculam esse
para as diferentes precisões (pelo menos “float” de máquina e, se possível, precisão simples e dupla).
Passo 2
O que é exatamente essa precisão e por que o algoritmo funciona (aula curta e prática).
- Definição usada aqui:
. Em palavras: o menor incremento positivo que, somado a 1, produz um valor maior que 1 na aritmética da máquina. - Por que existe um tal
: números em ponto flutuante têm mantissa com número finito de dígitos; após uma certa ordem de magnitude, incrementos muito pequenos são “arredondados” de volta para 1. - Relação com “unit roundoff”: muitas vezes se chama de unit roundoff
o valor tal que dependendo da definição adotada; aqui vamos estimar a definida acima (diferença entre 1 e o próximo número representável maior que 1). - Estratégia prática fácil de implementar: começar com
e ir dividindo por 2 enquanto . Quando o teste falhar, o último válido é a estimativa de . Motivo: se então ainda é um incremento detectável; quando diminuir mais e a soma for igual a 1 por arredondamento, então ultrapassou a resolução.
Passo 3
Pseudocódigo e advertências (para usar na prova sem biblioteca):
- Pseudocódigo simples:
-
- Enquanto
faça - Ao sair do laço,
é a estimativa de .
-
- Observações práticas:
- Use aritmética no tipo que quer testar (ex.: precisão simples vs dupla).
- Em linguagens com tipos explícitos (Fortran), declare a variável com o kind correto.
- Em Python, o tipo float é normalmente double (64 bits); para testar single (32 bits) use numpy.float32.
- Não confunda o critério: testar
diretamente pode falhar se começar com pequeno demais; por isso testamos com e dividimos sucessivamente.
Passo 4
Código Fortran (explicação linha-a-linha antes de mostrar o código):
- Ideia: usar duas variantes: precisão simples (single) e precisão dupla (double) com selected_real_kind para portabilidade.
- Estrutura:
- declarar kinds:
e com precisão típica (p~6 para single, p~15 para double); - inicializar eps = 1.0 do respectivo kind;
- laço do…end do que divide por 2 até o teste falhar;
- imprimir o resultado e comparar com a função intrínseca epsilon(x) (se disponível) para checagem.
- declarar kinds:
- Como compilar e executar (exemplo): use gfortran
- Compilar: gfortran -o eps_machine eps_machine.f90
- Executar: ./eps_machine
Código Fortran:
program machine_epsilon
implicit none
integer, parameter :: sp = selected_real_kind(p=6) ! precisão simples típica
integer, parameter :: dp = selected_real_kind(p=15) ! precisão dupla típica
real(kind=sp) :: one_sp, eps_sp, half_sp
real(kind=dp) :: one_dp, eps_dp, half_dp
one_sp = 1.0_sp
one_dp = 1.0_dp
! estimativa para precisão simples
eps_sp = 1.0_sp
do
half_sp = eps_sp / 2.0_sp
if (one_sp + half_sp <= one_sp) exit
eps_sp = half_sp
end do
! estimativa para precisão dupla
eps_dp = 1.0_dp
do
half_dp = eps_dp / 2.0_dp
if (one_dp + half_dp <= one_dp) exit
eps_dp = half_dp
end do
print *, 'Estimated machine epsilon (single) =', eps_sp
print *, 'Fortran intrinsic epsilon(one_sp) =', epsilon(one_sp)
print *, 'Estimated machine epsilon (double) =', eps_dp
print *, 'Fortran intrinsic epsilon(one_dp) =', epsilon(one_dp)
end program machine_epsilon
Passo 5
Código Python (explicação e variantes):
- Python float normal costuma ser double (64-bit). O código abaixo calcula
para float64. - Para testar float32 (precisão simples) usar numpy.float32 e fazer as operações com esse tipo.
- Também mostramos como comparar com numpy.finfo se numpy estiver disponível.
- Como executar: salvar em um arquivo .py e rodar python3 arquivo.py; se usar numpy instale com pip install numpy.
Código Python:
# Versão simples para float (double precision, Python float)
eps = 1.0
while 1.0 + eps/2.0 > 1.0:
eps /= 2.0
print("Estimated machine epsilon (Python float, double) =", eps)
# Versão usando numpy para testar float32 (single precision)
try:
import numpy as np
eps32 = np.float32(1.0)
one32 = np.float32(1.0)
two32 = np.float32(2.0)
while np.float32(one32 + eps32/two32) > one32:
eps32 = np.float32(eps32 / two32)
print("Estimated machine epsilon (numpy.float32, single) =", eps32)
# comparação com numpy.finfo
print("numpy.finfo(np.float64).eps =", np.finfo(np.float64).eps)
print("numpy.finfo(np.float32).eps =", np.finfo(np.float32).eps)
except ImportError:
print("numpy não está disponível. Para testar float32 instale numpy (pip install numpy).")
Passo 6
Exemplo de saída esperada e interpretação (para você entender o que verá):
- Em muitas máquinas modernas:
-
para double (float64) costuma ser aproximadamente . -
para single (float32) costuma ser aproximadamente .
-
- Interpretação: se a sua execução der esses valores (ou muito próximos), seu compilador/implementação segue o padrão IEEE-754 típico. Pequenas diferenças são possíveis em arquiteturas exóticas ou compiladores com opções de otimização agressivas.
Passo 7
Dicas finais e verificações extras que ajudam na prova e no uso prático:
- Fortran tem a função intrínseca
que retorna precisamente esse valor para o tipo de ; o programa acima imprime para checar. - Em Python com numpy, use
para obter diretamente. - Para testes de comparação com zero na prova/algoritmo, escolha um tolerância tol baseada em
, por exemplo ou dependendo da sensibilidade exigida. - Incentivo: rode os códigos agora mesmo — é rápido — e veja os valores na sua máquina. Se der problema, me manda o erro que eu te ajudo a corrigir.
Resposta
Fortran:
program machine_epsilon
implicit none
integer, parameter :: sp = selected_real_kind(p=6) ! precisão simples típica
integer, parameter :: dp = selected_real_kind(p=15) ! precisão dupla típica
real(kind=sp) :: one_sp, eps_sp, half_sp
real(kind=dp) :: one_dp, eps_dp, half_dp
one_sp = 1.0_sp
one_dp = 1.0_dp
! estimativa para precisão simples
eps_sp = 1.0_sp
do
half_sp = eps_sp / 2.0_sp
if (one_sp + half_sp <= one_sp) exit
eps_sp = half_sp
end do
! estimativa para precisão dupla
eps_dp = 1.0_dp
do
half_dp = eps_dp / 2.0_dp
if (one_dp + half_dp <= one_dp) exit
eps_dp = half_dp
end do
print *, 'Estimated machine epsilon (single) =', eps_sp
print *, 'Fortran intrinsic epsilon(one_sp) =', epsilon(one_sp)
print *, 'Estimated machine epsilon (double) =', eps_dp
print *, 'Fortran intrinsic epsilon(one_dp) =', epsilon(one_dp)
end program machine_epsilon
Python:
# Versão simples para float (double precision, Python float)
eps = 1.0
while 1.0 + eps/2.0 > 1.0:
eps /= 2.0
print("Estimated machine epsilon (Python float, double) =", eps)
# Versão usando numpy para testar float32 (single precision)
try:
import numpy as np
eps32 = np.float32(1.0)
one32 = np.float32(1.0)
two32 = np.float32(2.0)
while np.float32(one32 + eps32/two32) > one32:
eps32 = np.float32(eps32 / two32)
print("Estimated machine epsilon (numpy.float32, single) =", eps32)
# comparação com numpy.finfo
print("numpy.finfo(np.float64).eps =", np.finfo(np.float64).eps)
print("numpy.finfo(np.float32).eps =", np.finfo(np.float32).eps)
except ImportError:
print("numpy não está disponível. Para testar float32 instale numpy (pip install numpy).")