Problemas com calculo de ponto flutuante

7 respostas
L

Ola… estou com problemas para calcular porcentagem de valores e somalas… a soma nunca dara 100% e sim um numero aproximado… pois as parcelas são valores de até varias casas decimais… ja tentei varios tipos de arrendondamento com o BigDecimal (HALF_UP, UP, DOWN, etc…) mas não obtive sucesso… qual seria a melhor forma de fazer isto? e como posso fazer calculos de prexisão exata com pontos flutuantes sem perca de valores? podemos ver que calculos deste tipo ao final podem gerar devida perda de valor… como pode trabalhar com isto com maxima precisão???

7 Respostas

L

Olá

Sim, como eu mesmo já expliquei várias vezes aqui no GUJ, representar números de pontos flutuantes em computadores digitais (qualquer que seja a linguagem) pode precisar truncar o número para caber nos bits.

Dá para trabalhar? É claro que sim pois senão Fortran nem existiria pois no seu uso em quase tudo envolve cálculos com números de ponto flutuante.

Como fazemos? Simples, fazemos todos os cálculos com precisão a menos de um número muito pequeno cuja influência depende do problema.

Exemplo: 5 / 3 = (5 * 3) + DELTA onde DELTA é um número muito pequeno tal como 10 ** (-17)
Então a gente sempre compara com o DELTA
if (( (5/3)* 3 - 5) <= DELTA) é true

Cuidado com arredondamentos no meio do cálculo porque estará incluindo erros nas contas. A gente só pode arredondar no fim do cálculo.

[]s
Luca

L

Cara naum entendi mto bem a sua pergunta naum, mas pelo que eu entendi vc quer arredondar um número é isso?
se for isso tenta usar o printf.
por exemplo:

System.out.printf(“Saldo da Conta: $%.2f”, saldo);

ai com isso ele imprime com dois numeros decimais depois da virgula e arredonda.
espero ter ajudado.

L

Olá

lopima:
Cara naum entendi mto bem a sua pergunta naum, mas pelo que eu entendi vc quer arredondar um número é isso?
se for isso tenta usar o printf.
por exemplo:

System.out.printf(“Saldo da Conta: $%.2f”, saldo);

ai com isso ele imprime com dois numeros decimais depois da virgula e arredonda.
espero ter ajudado.

Desculpe corrigí-lo mas para arredondar números de ponto flutuante há meios MUITO melhores e menos custosos do que usar printf. Nem vou citar para não lhe tirar o prazer de pensar um pouquinho.

[]s
Luca

L

thingol eu não entendi muito bem este esquema… o que seria o DELTA? como seria esta formula e aonde e como iria arredondar??? não entendi este procedimento…

e printf não me ajuda em nada… estou usando isto em um relatorio excel e não na tela do console…

o problema é: tenho uma tabela com n linha e n colunas com valores decimais ele devera somar todas as colunas de e totalizar a cada linha com a porcentagem referente a cada linha. No final deve somar todos as porcentagens totalizadoras de cada linha e obter o percentual final de 100%… a cada linha ja estou formatando o percentual em 2 casas decimais mas ao final qdo somar todos os totalizadores nunca obterei o valor de 100% e sim apenas um valor aproximado…

e outro problema é a perca de valores com a totalização e arrendondamento em cada linha…

L

Olá

[]s
Luca

R

dê uma olhada neste tópico

http://www.guj.com.br/posts/list/75747.java#398656

D

Bom, como você já deve ter visto e com a ajuda dos posts acima, percebeu que trabalhar com números assim não é tão fácil quanto deveria.

Com o método mencionado pelo Luca você até consegue trabalhar, mas é um pouco confuso. Já a classe do ricardosoares parece bem interessante, seria bom você testar

Eu costumo utilizar, junto com BigDecimal, a classe MathContext em seus cálculos, que definirá uma precisão e um modo de arredondamento.

Também é importante você criar seus objetos da classe BigDecimal a partir de strings, sem converter, assim não há "surpresas" devido a representação interna dos ponto-flutuantes.

Segue um código pra você ter como exemplo:

package com.dudaskank;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

/**
 * Mostrando o {@link BigDecimal} usando o {@link MathContext}
 *
 * @author Eduardo Oliveira
 *
 */
public class TesteBigDecimal {

	public static void main(String[] args) {
		String valoresString[] = { "2.37", "5.20", "0.86", "21.40", "9.56",
				"13.13", "12.29" };
		BigDecimal cem, valores[], porcento[], porcentoSemMC[], total, totalPorcento, totalPorcentoSemMC;

		total = new BigDecimal("0", MathContext.DECIMAL128);
		valores = new BigDecimal[valoresString.length];
		// converte e calcula o total
		for (int i = 0; i < valoresString.length; i++) {
			valores[i] = new BigDecimal(valoresString[i], MathContext.DECIMAL128);
			total = total.add(valores[i], MathContext.DECIMAL128);
		}
		// calcula o percentual e seu total, com e sem MathContext
		cem = new BigDecimal("100", MathContext.DECIMAL128);
		totalPorcento = new BigDecimal("0", MathContext.DECIMAL128);
		totalPorcentoSemMC = new BigDecimal("0");
		porcento = new BigDecimal[valoresString.length];
		porcentoSemMC = new BigDecimal[valoresString.length];
		for (int i = 0; i < valores.length; i++) {
			porcento[i] = valores[i].multiply(cem, MathContext.DECIMAL128).divide(total, MathContext.DECIMAL128);
			totalPorcento = totalPorcento.add(porcento[i],
					MathContext.DECIMAL128);

			porcentoSemMC[i] = valores[i].multiply(BigDecimal.valueOf(100))
			.divide(total, 8, RoundingMode.HALF_EVEN);
			totalPorcentoSemMC = totalPorcentoSemMC.add(porcentoSemMC[i]);
		}
		// mostra os resultados na tela
		for (int i = 0; i < valores.length; i++) {
			System.out.printf("%.2f\t%f%%\t%f%%\n", valores[i], porcento[i],
					porcentoSemMC[i]);
		}
		System.out.println("------------------------------------");
		System.out.printf("%.2f\t%f%%\t%f%%\n", total, totalPorcento,
				totalPorcentoSemMC);
	}

}

Faça um teste com todas as soluções e escolha uma que você se sinta bem utilizando, e boa sorte

Criado 7 de maio de 2008
Ultima resposta 7 de mai. de 2008
Respostas 7
Participantes 5