Problema de cálculo

2 respostas
judac

Pessoal,

Na empresa começamos a traduzir um projeto legado desenvolvido em C++ para Java.  que não conseguimos alcançar os mesmo resultados. Após alguns testes detectamos que o C++ tem um problema de aproximação, mas posteriormente detectamos que o Java tbm tém. O problema é que eles "eram" em locais diferente.

O que vocês acham que deveria dar a execução do código abaixo??? IF ou ELSE???

double c = 32.2 - 32.1;
	double d = 30.2 - 30.1;
		
	System.out.println("c: "+ c);
	System.out.println("d: "+ d);
		
	if (c == d)
		System.out.println("worked!!!");
	else
		System.out.println("better luck next time!!!");

Para a surpresa de todos, dá ELSE??? Existe alguma workaround para minimizar este tipo de erro??? Estamos temporariamente utilizando o NumberFormat, contudo dependendo da precisão não resolve.

Abraços

inté!

2 Respostas

R

Esse tipo de problema é clássico na manipulação de números de ponto flutuante. Devido à natureza da representação interna dos números de ponto flutuante na maioria dos processadores, muitas vezes é difícil armazenar um número de forma "exata". Para evitar esse problema, uma saída é usar margens de tolerância em vez de comparações exatas:

double c = 32.2d - 32.1d;
double d = 30.2d - 30.1d;

System.out.println("c: "+ c);
System.out.println("d: "+ d);

if (Math.abs(c - d) <= 0.001d)
  System.out.println("worked!!!");
else
  System.out.println("better luck next time!!!");

Você pode obter exatidão "perfeita" com a classe BigDecimal, mas tenha em mente que o desempenho dela é menor que o uso de variáveis primitivas do tipo double e float.

T

Uma coisa curiosa do C/C++/Delphi e outras linguagens compiladas para código nativo (em relação ao Java) é que ele pode fazer contas e dar resultados diferentes, dependendo das opções de compilação e do processador para o qual essas linguagens serão compiladas.

Isso é mais notório em máquinas Intel, onde os resultados intermediários são calculados internamente em 80 bits, mesmo que as variáveis usadas sejam float (32 bits) ou double (64 bits).

Como isso ocorre no C, o Java optou por definir um determinado método de cálculo para que os resultados não fiquem sendo diferentes. No Java os resultados intermediários de contas com double (64 bits) devem sempre ser calculados em 64 bits, e os resultados intermediários de contas com float (32 bits) devem sempre ser calculados em 32 bits. Isso tem até uma vantagem - nas máquinas Intel mais novas, existe a possibilidade de efetuar cálculos intermediários em 32 ou 64 bits usando as instruções SSE, SSE2, SSE3 ou SSE4, e essas instruções são mais rápidas que as instruções de ponto flutuante clássicas (FADD, FSUB etc.).

Criado 15 de maio de 2009
Ultima resposta 15 de mai. de 2009
Respostas 2
Participantes 3