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???
Problemas com calculo de ponto flutuante
7 Respostas
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
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.
Olá
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
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…
Olá
[]s
Luca
dê uma olhada neste tópico
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