Portanto, tenho um conjunto duplo igual a 1234, quero mover uma casa decimal para 12,34
Então, para fazer isso, multiplico 0,1 a 1234 duas vezes, mais ou menos assim
double x = 1234;
for(int i=1;i<=2;i++)
{
x = x*.1;
}
System.out.println(x);
Isso imprimirá o resultado, "12.340000000000002"
Existe uma maneira, sem simplesmente formatá-lo com duas casas decimais, de ter o armazenamento duplo 12,34 corretamente?
x /= 100;
?Respostas:
Se você usar
double
oufloat
, deverá usar arredondamento ou poderá ver alguns erros de arredondamento. Se você não pode fazer isso, useBigDecimal
.O problema que você tem é que 0,1 não é uma representação exata e, ao realizar o cálculo duas vezes, você está agravando esse erro.
No entanto, 100 pode ser representado com precisão, então tente:
que imprime:
Isso funciona porque
Double.toString(d)
executa um pequeno arredondamento por você, mas não é muito. Se você está se perguntando como seria a aparência sem arredondamentos:estampas:
Em suma, o arredondamento é inevitável para respostas sensatas em ponto flutuante, esteja você fazendo isso explicitamente ou não.
Nota:
x / 100
ex * 0.01
não são exatamente os mesmos quando se trata de erros de arredondamento. Isso ocorre porque o erro de arredondamento para a primeira expressão depende dos valores de x, enquanto o0.01
da segunda tem um erro de arredondamento fixo.estampas
fonte
1234/100
, como você fez, realmente não faz nada sobre o problema subjacente - deve ser exatamente igual a escrever1234 * 0.01
./100
e*0.01
são equivalentes entre si, mas não aos OPs*0.1*0.1
.Não - se você quiser armazenar valores decimais com precisão, use
BigDecimal
.double
simplesmente não pode representar um número exatamente como 0,1, mais do que você pode escrever o valor de um terço exatamente com um número finito de dígitos decimais.fonte
se for apenas formatação, tente printf
resultado
fonte
System.out.printf()
é o caminho certo a seguir.Em software financeiro, é comum usar números inteiros por centavos. Na escola, fomos ensinados a usar ponto fixo em vez de flutuar, mas isso geralmente é potências de dois. O armazenamento de moedas de um centavo em números inteiros também pode ser chamado de "ponto fixo".
Em aula, fomos questionados em geral sobre quais números podem ser representados exatamente em uma base.
Para
base=p1^n1*p2^n2
... você pode representar qualquer N onde N = n * p1 ^ m1 * p2 ^ m2.Deixe
base=14=2^1*7^1
... você pode representar 1/7 1/14 1/28 1/49, mas não 1/3Eu sei sobre software financeiro - converti os relatórios financeiros da Ticketmaster do VAX asm para PASCAL. Eles tinham seu próprio formatln () com códigos para centavos. O motivo da conversão foi que inteiros de 32 bits não eram mais suficientes. +/- 2 bilhões de centavos é $ 20 milhões e isso transbordou para a Copa do Mundo ou as Olimpíadas, esqueci.
Eu jurei segredo. Ah bem. Na academia, se for bom você publica; na indústria, você mantém isso em segredo.
fonte
você pode tentar a representação de um número inteiro
fonte
r
for menor que 10, nenhum preenchimento de 0 ocorrerá e 1204 produzirá um resultado de 12,4. A string de formatação correta é mais semelhante a "% d.% 02d"Isso é causado pela maneira como os computadores armazenam números de ponto flutuante. Eles não fazem exatamente isso. Como programador, você deve ler este guia de ponto flutuante para se familiarizar com as tentativas e tribulações de lidar com números de ponto flutuante.
fonte
Engraçado que vários posts mencionam o uso de BigDecimal, mas ninguém se preocupa em dar a resposta correta com base em BigDecimal? Porque mesmo com BigDecimal, você ainda pode dar errado, como demonstrado por este código
Dá esta saída
O construtor BigDecimal menciona especificamente que é melhor usar o construtor String do que um construtor numérico. A precisão máxima também é influenciada pelo MathContext opcional.
De acordo com o Javadoc BigDecimal , é possível criar um BigDecimal que seja exatamente igual a 0,1, desde que você use o construtor String.
fonte
Sim existe. Com cada operação dupla, você pode perder a precisão, mas a quantidade de precisão difere para cada operação e pode ser minimizada escolhendo a sequência correta de operações. Por exemplo, ao multiplicar um conjunto de números, é melhor classificar o conjunto pelo expoente antes de multiplicar.
Qualquer livro decente sobre análise de números descreve isso. Por exemplo: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
E para responder à sua pergunta:
Use dividir em vez de multiplicar, dessa forma você obterá o resultado correto.
fonte
Não, como os tipos de ponto flutuante Java (na verdade, todos os tipos de ponto flutuante) são uma compensação entre tamanho e precisão. Embora sejam muito úteis para muitas tarefas, se você precisa de precisão arbitrária, deve usar
BigDecimal
.fonte