Jump to content
Sign in to follow this  
_Rest_

Erro de calculo Java

Recommended Posts

_Rest_

Só por curiosidade, alguém me explica o porquê do Java fazer este erro de calculo

public class Exercicio2 
{

public static void main(String[] args) 
{

	double valor=0.00;
	int moedas[]= new int[8];


	Scanner valorScan = new Scanner (System.in);

	System.out.println("Introduza o valor ");
	valor = valorScan.nextDouble();
	valorScan.nextLine();
	while (valor !=0.00)
	{
		System.out.println("teste "+valor);
		if (valor >= 2.00)
		{
		valor = valor-2.00;
		moedas[0]++;
		}
		else if (valor >= 1.00 && valor < 2.00)
		{
		valor = valor -1.00;
		moedas[1]++;
		}
		else if (valor >= 0.50 && valor < 1.00)
		{
		valor = valor -0.50;
		moedas[2]++;
		}
		else if (valor >= 0.20 && valor < 0.50)
		{
		valor = valor -0.20;
		moedas[3]++;
		}
		else if (valor >= 0.10 && valor < 0.20)
		{
		valor = valor -0.10;
		moedas[4]++;
		}
		else if (valor >= 0.05 && valor < 0.10)
		{
		valor = valor -0.05;
		moedas[5]++;
		}
		else if (valor >= 0.02 && valor < 0.05)
		{
		valor = valor -0.02;
		moedas[6]++;
		}
		else if (valor >= 0.01 && valor < 0.02)
		{
		valor = valor -0.01;
		moedas[7]++;
		}
	}
	System.out.println("moedas de 2€: "+moedas[0]+" moedas de 1€: "+moedas[1]+" moedas de 0.50€: "+moedas[2]+" moedas de 0.20€: "+moedas[3]+" moedas de 0.10€: "+moedas[4]+" moedas de 0.05€: "+moedas[5]+" moedas de 0.02€: "+moedas[6]+" moedas de 0.01€: "+moedas[7]);

}

}

no output ele faz

Introduza o valor

4,75

teste 4.75

teste 2.75

teste 0.75

teste 0.25

teste 0.04999999999999999

teste 0.02999999999999999

teste 0.009999999999999988

ele quando subtrai os 0.20 faz mal o calculo. Já me tinha deparado com isso quando num programa para gerir uma vending machine a devolução de moedas dava erro. Tive que passar para cêntimos para poder fazer ficando assim:

	static void DevoluçãoMoedas(double troco)
{
	int i=0;
	troco=(int)(troco*100);
	while (troco!=0.00)
	{	
		i=0;
		if (troco%2!=0)
		{
			troco= troco-5;
			Nmoedas[0][0]=Nmoedas[0][0]-1;
		}
		System.out.println("troco  "+troco);
		if (troco>=50 && Nmoedas[3][0]>0)
		{
			troco= troco-50;
			Nmoedas[3][0]=Nmoedas[3][0]-1;
			i=1;
		}
		if (i==0 && troco>=20 && Nmoedas[2][0]>0) 
		{
			troco= troco-20;
			Nmoedas[2][0]=Nmoedas[2][0]-1;
			i=1;
		}
		if (i==0 && troco>=10 && Nmoedas[1][0]>0) 
			{
			troco= troco-10;
			Nmoedas[1][0]=Nmoedas[1][0]-1;
			i=1;
			}
	}
	troco=troco/100;
ActualizarMoedas();
}

Share this post


Link to post
Share on other sites
M6

Um workaround que costuma funcionar passa por converteres para string e depois para numérico novamente.


10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Share this post


Link to post
Share on other sites
pedrotuga

É um workaround pouco elegante na minha opinião.

Eu sugiro uma classe de formatação de números que serve precisamente para isso:

http://download.oracle.com/javase/tutorial/java/data/numberformat.html

Os números nem sempre são o que parecem. 0.05 é impossível representar com um double, então a jvm usa o que tiver mais próximo que é: 0.04999999999999999

Falcon, verifica o conteudo dos links antes de afixar, um é um link para comprar um pdf e o outro é a página da wikipédia sobre a especificação que não contem os detales técnicos.

Este link tem mais detalhe sobre como funcionam os floats:

http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.3

_Rest_ este comportamento é o esperado, o erro é introduzido porque é inevitável. Mas recorrendo a arredondamentos simples (ver o primeiro link) resolver o problema para a maior parte das situações. Se precisares de precisão, tens que usar um tipo de dados numérico de precisão arbitrária, o double é de precisão finita, mas duvido que seja o caso. Pelo tipo de exercício, diria que até o teu professor é capaz de nem saber do que estamos aqui a falar.

Share this post


Link to post
Share on other sites
M6

Nenhum workaround é elegante, é por isso que é um workaround...


10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Share this post


Link to post
Share on other sites
shumy

Valores monetários nunca devem usar vírgula flutuante já por causa destas coisas.


Aqui há coisa de 2 anos fazia umas malhas de croché, depois fartei-me e fui para informática!

Share this post


Link to post
Share on other sites
pedrotuga

Nenhum workaround é elegante, é por isso que é um workaround...

Bem observado.

Valores monetários nunca devem usar vírgula flutuante já por causa destas coisas.

Isso não é um pouco overkill? A documentação oficial diz precisamente isso, mas acho isso um pouco exagerado. Transferindo de forma grosseira simplificada, a quantos algarismos significativos decimais corresponde a precisão de um double ? Olhando para o exemplo deste tópico, eu diria uns 14.

Sinceramente, duvido que a esmagadora maioria das empresas, ou outras entidades que mexam com valores monetários, precisem de mais de nove. Diria mesmo que na maior parte dos casos até 8 chegam.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.