ID do artigo: 125056 - Última revisão: quinta-feira, 24 de fevereiro de 2005 - Revisão: 2.1

INFO: A precisão e precisão em cálculos de ponto flutuante

Dica do SistemaEste artigo aplica-se a um sistema operativo diferente do que está a utilizar. Foi desactivado o conteúdo do artigo, que pode não ser relevante para si.

Nesta página

Expandir tudo | Recolher tudo

Sumário

Há várias situações em que precisão, arredondamento, e precisão nos cálculos de ponto flutuante pode trabalhar para gerar resultados surpreendentes para o programador. Há quatro regras gerais que devem ser seguidas:
  1. Em um cálculo envolvendo precisão simples e dupla, o resultado não geralmente serão qualquer mais preciso de precisão única. Se a precisão dupla for necessária, ter certeza de todos os termos no cálculo, incluindo constantes, são especificados na precisão dupla.
  2. Nunca suponha que um valor numérico simples com precisão é representado no computador. Mais valores de ponto flutuante não podem ser representados com precisão como um valor binário finito. Por exemplo, 0,1 é.0001100110011... em binário (ele se repita para sempre), portanto, não pode ser representada com precisão total em um computador usando binário aritmético, que inclui todos os PCs.
  3. Nunca presuma que o resultado é preciso para a última casa decimal. Sempre há pequenas diferenças entre a resposta "true" e o que pode ser calculado com a precisão finita de qualquer unidade de processamento de ponto flutuante.
  4. Nunca compare dois valores de ponto flutuante para ver se elas são não-igual ou igual. Este é um resultado a regra 3. Há quase sempre serão pequenas diferenças entre os números "devem" ser iguais. Em vez disso, sempre verifique se os números são quase iguais. Em outras palavras, verifique se a diferença entre eles é muito pequeno ou.

Mais Informações

Em geral, as regras descritas acima se aplicam a todos os idiomas, incluindo C, C++ e montador. Os exemplos abaixo demonstram alguns das regras usando FORTRAN PowerStation. Todos os exemplos foram compilados usando FORTRAN PowerStation 32 sem opções, exceto para o último, que está escrito na C.

Consulte os manuais do FORTRAN fornecido com o Microsoft FORTRAN para uma descrição das constantes numéricas e artigo 36068  (http://support.microsoft.com/kb/36068/EN-US/ ) para obter uma descrição da representação interna dos valores de ponto flutuante.

EXEMPLO 1

O primeiro exemplo demonstra duas coisas:

  • Que FORTRAN constantes são precisão única por padrão (constantes C são precisão dupla por padrão).
  • Cálculos que contêm os termos de precisão única não são muito mais precisos de cálculos em que todos os termos são precisão única.
Depois que está sendo inicializado com 1.1 (uma constante de precisão única), y é como impreciso como uma variável de precisão única.
   x = 1.100000000000000  y = 1.100000023841858
				
o resultado da multiplicação de um valor de precisão única por um valor preciso precisão dupla é quase tão ruim quanto multiplicar dois valores de precisão única. Ambos os cálculos tem milhares de vezes quanto erro como multiplicar dois valores de precisão dupla.
   true = 1.320000000000000 (multiplying 2 double precision values)
   y    = 1.320000052452087 (multiplying a double and a single)
   z    = 1.320000081062318 (multiplying 2 single precision values)
				

Código de exemplo

C Compile options: none

       real*8 x,y,z
       x = 1.1D0
       y = 1.1
       print *, 'x =',x, 'y =', y
       y = 1.2 * x
       z = 1.2 * 1.1
       print *, x, y, z
       end
				

EXEMPLO 2

Exemplo 2 usa a equação quadrática. Ele demonstra que os cálculos de precisão dupla mesmo não são perfeitos e que o resultado de um cálculo deve ser testado antes que ele é dependentes se erros pequenos podem apresentar resultados drásticas. A entrada para a função raiz quadrada no exemplo 2 somente é negativa muito pouco, mas não é válido ainda. Se os cálculos de precisão dupla não tem erros leves, o resultado seria:
   Root =   -1.1500000000
				
em vez disso, ele gera o seguinte erro:
Erro em tempo de execução M6201: MATEMÁTICA
-sqrt: erro de domínio

Código de exemplo

C Compile options: none

       real*8 a,b,c,x,y
       a=1.0D0
       b=2.3D0
       c=1.322D0
       x = b**2
       y = 4*a*c
       print *,x,y,x-y
       print "(' Root =',F16.10)",(-b+dsqrt(x-y))/(2*a)
       end
				

EXEMPLO 3

Exemplo 3 demonstra que devido à otimizações que ocorrer mesmo se a otimização não estiver ativada, valores podem temporariamente manter uma precisão maior que o esperado, e que é muito imprudente testar dois valores de ponto flutuante de igualdade.

Neste exemplo, dois valores são iguais e não igual. No primeiro se, o valor de Z ainda está na pilha do co-processador e tem a mesma precisão como Y. X, portanto, não é igual Y e a primeira mensagem é impressa. No momento da se segundo, Z tinha a ser carregado na memória e, portanto, tinha a mesma precisão e o valor como X e a segunda mensagem também é impresso.

Código de exemplo

C Compile options: none

       real*8 y
       y=27.1024D0
       x=27.1024
       z=y
       if (x.ne.z) then
         print *,'X does not equal Z'
       end if
       if (x.eq.z) then
         print *,'X equals Z'
       end if
       end
				

EXEMPLO 4

A primeira parte do código de exemplo 4 calcula a menor diferença possível entre dois números próximo a 1.0. Ele faz isso adicionando um único bit a representação binária de 1.0.
   x   = 1.00000000000000000  (one bit more than 1.0)
   y   = 1.00000000000000000  (exactly 1.0)
   x-y =  .00000000000000022  (smallest possible difference)
				
algumas versões do FORTRAN arredondar números quando exibi-los para que o inerente numéricos imprecision não é tão óbvio. É por isso que x e y parecem iguais quando exibidos.

A segunda parte do código de exemplo 4 calcula a menor diferença possível entre os 2 números perto para 10.0. Novamente, ele faz isso adicionando um único bit a representação binária de 10.0. Observe que a diferença entre os números quase 10 é maior do que a diferença próximo a 1. Isso demonstra o princípio geral que quanto maior o valor absoluto de um número, com menor precisão ele pode ser armazenado em um determinado número de bits.
   x   = 10.00000000000000000  (one bit more than 10.0)
   y   = 10.00000000000000000  (exactly 10.0)
   x-y =   .00000000000000178
				
a representação binária desses números também é exibida para mostrar o que diferem apenas um bit.
   x = 4024000000000001 Hex
   y = 4024000000000000 Hex
				
a última parte do código de exemplo 4 mostra que simples valores decimais não-repetição com freqüência podem ser representados em binário somente por uma fração de repetição. Neste caso x = 1.05, que requer um fator de repetição CCCCCCCC....(Hex) o mantissa. Em FORTRAN, o último dígito "C" é arredondado para "D" para manter a maior precisão possível:
   x = 3FF0CCCCCCCCCCCD (Hex representation of 1.05D0)
				
mesmo depois de arredondamento, o resultado não é preciso perfeitamente. Há algum erro após o dígito menos significativo, o que podemos ver, removendo o primeiro dígito.
   x-1 = .05000000000000004
				

Código de exemplo

C Compile options: none

       IMPLICIT real*8 (A-Z)
       integer*4 i(2)
       real*8 x,y
       equivalence (i(1),x)

       x=1.
       y=x
       i(1)=i(1)+1
       print "(1x,'x  =',F20.17,'  y=',f20.17)", x,y
       print "(1x,'x-y=',F20.17)", x-y
       print *

       x=10.
       y=x
       i(1)=i(1)+1
       print "(1x,'x  =',F20.17,'  y=',f20.17)", x,y
       print "(1x,'x-y=',F20.17)", x-y
       print *
       print "(1x,'x  =',Z16,' Hex  y=',Z16,' Hex')", x,y
       print *

       x=1.05D0
       print "(1x,'x  =',F20.17)", x
       print "(1x,'x  =',Z16,' Hex')", x
       x=x-1
       print "(1x,'x-1=',F20.17)", x
       print *

       end
				

EXEMPLO 5

No C, constantes flutuantes são duplicatas por padrão. Use um "f" para indicar um valor de ponto flutuante, como em "89.95f".
   /* Compile options needed: none
   */ 

   #include <stdio.h>

   void main()
   {
      float floatvar;
      double doublevar;

   /* Print double constant. */ 
      printf("89.95 = %f\n", 89.95);      // 89.95 = 89.950000

   /* Printf float constant */ 
      printf("89.95 = %f\n", 89.95F);     // 89.95 = 89.949997

   /*** Use double constant. ***/ 
      floatvar = 89.95;
      doublevar = 89.95;

      printf("89.95 = %f\n", floatvar);   // 89.95 = 89.949997
      printf("89.95 = %lf\n", doublevar); // 89.95 = 89.950000

   /*** Use float constant. ***/ 
      floatvar = 89.95f;
      doublevar = 89.95f;

      printf("89.95 = %f\n", floatvar);   // 89.95 = 89.949997
      printf("89.95 = %lf\n", doublevar); // 89.95 = 89.949997
   }
				

A informação contida neste artigo aplica-se a:
  • Microsoft FORTRAN PowerStation 1.0 Standard Edition
  • Microsoft Fortran PowerStation 1.0a for MS-DOS
  • Microsoft FORTRAN PowerStation 32
  • Microsoft Visual C++ 1.0 Professional Edition
  • Microsoft Visual C++ 1.5 Professional Edition
  • Microsoft Visual C++ 1.51
  • Microsoft Visual C++ 2.0 Professional Edition
  • Microsoft Visual C++ 4.0 Standard Edition
  • Microsoft Visual C++ 5.0 Enterprise Edition
  • Microsoft Visual C++ 6.0 Enterprise Edition
  • Microsoft Visual C++ 5.0 Professional Edition
  • Microsoft Visual C++ 6.0 Professional Edition
  • Microsoft Visual C++, 32-bit Learning Edition 6.0
Palavras-chave: 
kbmt kbcode kbinfo kblangc kblangfortran KB125056 KbMtpt
Tradução automáticaTradução automática
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine Translation ou MT), não tendo sido portanto traduzido ou revisto por pessoas. A Microsoft possui artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais, com o objetivo de oferecer em português a totalidade dos artigos existentes na base de dados de suporte. No entanto, a tradução automática não é sempre perfeita, podendo conter erros de vocabulário, sintaxe ou gramática. A Microsoft não é responsável por incoerências, erros ou prejuízos ocorridos em decorrência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza atualizações freqüentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 125056  (http://support.microsoft.com/kb/125056/en-us/ )