por exemplo, com o dólar, você nunca tem precisão inferior a US $ 0,01
Sério?
a questão antiga de por que você não deve armazenar moeda como um número de ponto flutuante IEEE 754.
Sinta-se à vontade para armazenar polegadas nos números de ponto flutuante IEEE 754 . Eles armazenam exatamente como você esperaria.
Sinta-se à vontade para armazenar qualquer quantia de dinheiro nos números de ponto flutuante IEEE 754 que você pode armazenar usando os ticks que dividem uma régua em frações de polegada.
Por quê? Porque quando você usa o IEEE 754, é assim que você o armazena.
O problema das polegadas é que elas são divididas em duas partes. A coisa sobre a maioria dos tipos de moeda é que eles são divididos em décimos (alguns tipos não são, mas vamos manter o foco).
Essa diferença não seria tão confusa, exceto que, para a maioria das linguagens de programação, a entrada e saída dos números de ponto flutuante IEEE 754 é expressa em decimais! O que é muito estranho, porque eles não são armazenados em decimais.
Por causa disso, você nunca consegue ver como os bits fazem coisas estranhas quando você pede ao computador para armazenar 0.1
. Você só vê a estranheza quando faz contas contra ela e ela apresenta erros estranhos.
Do java eficaz de Josh Bloch :
System.out.println(1.03 - .42);
Produz 0.6100000000000001
O que é mais revelador sobre isso não é o 1
caminho para a direita. São os números estranhos que precisavam ser usados para obtê-lo. Em vez de usar o exemplo mais popular, 0.1
precisamos usar um exemplo que mostre o problema e evite o arredondamento que o ocultaria.
Por exemplo, por que isso funciona?
System.out.println(.01 - .02);
Produz -0.01
Porque nós tivemos sorte.
Eu odeio problemas difíceis de diagnosticar porque às vezes tenho "sorte".
O IEEE 754 simplesmente não pode armazenar 0,1 com precisão. Mas se você pedir para armazenar 0,1 e depois imprimir, será exibido 0,1 e você achará que está tudo bem. Não está bom, mas você não pode ver isso porque está arredondando para voltar a 0,1.
Algumas pessoas confundem os outros chamando essas discrepâncias de arredondamento de erros. Não, estes não são erros de arredondamento. O arredondamento está fazendo o que deveria e transformando o que não é decimal em decimal, para que possa ser impresso na tela.
Mas isso oculta a incompatibilidade entre como o número é exibido e como é armazenado. O erro não ocorreu quando o arredondamento aconteceu. Aconteceu quando você decidiu inserir um número em um sistema que não pode armazená-lo com precisão e supôs que ele estava sendo armazenado com precisão quando não estava.
Ninguém espera que π seja armazenado com precisão em uma calculadora e eles conseguem trabalhar com ela muito bem. Portanto, o problema não é sequer sobre precisão. É sobre a precisão esperada. Os computadores exibem um décimo 0.1
da mesma forma que nossas calculadoras, portanto esperamos que eles armazenem um décimo perfeitamente da maneira que nossas calculadoras. Eles não. O que é surpreendente, já que os computadores são mais caros.
Deixe-me mostrar a incompatibilidade:
Observe que 1/2 e 0,5 se alinham perfeitamente. Mas 0.1 simplesmente não se alinha. Claro que você pode se aproximar se continuar dividindo por 2, mas nunca acertará exatamente. E precisamos de mais e mais bits cada vez que dividimos por 2. Portanto, representar 0,1 com qualquer sistema que divida por 2 precisa de um número infinito de bits. Meu disco rígido não é tão grande assim.
Portanto, o IEEE 754 para de tentar quando fica sem bits. O que é legal porque preciso de espaço no meu disco rígido para ... fotos de família. Não mesmo. Fotos de família. : P
De qualquer forma, o que você digita e o que vê são decimais (à direita), mas o que você armazena são bicimais (à esquerda). Às vezes, esses são perfeitamente iguais. Às vezes não são. Às vezes, parece que são iguais quando simplesmente não são. Esse é o arredondamento.
Em particular, o que precisamos saber para poder armazenar valores em alguma moeda e imprimi-los?
Por favor, se você estiver lidando com meu dinheiro com base decimal, não use carros alegóricos ou duplos.
Se você tem certeza de que coisas como décimos de centavos não estarão envolvidas, basta guardar centavos. Caso contrário, descubra qual será a menor unidade dessa moeda e use-a. Se não puder, use algo como BigDecimal .
Meu patrimônio líquido provavelmente sempre se encaixará perfeitamente em um número inteiro de 64 bits, mas coisas como o BigInteger funcionam bem em projetos maiores que isso. Eles são apenas mais lentos que os tipos nativos.
Descobrir como armazenar é apenas metade do problema. Lembre-se de que você também deve poder exibi-lo. Um bom design separará essas duas coisas. O verdadeiro problema com o uso de carros alegóricos aqui é que essas duas coisas são misturadas.