Ninguém nasce Sênior, se torna Sênior!
Se tornar um Sênior é um processo demorado, e requer muito suor. Como o mercado de computação tem se expandido exponencialmente, resolvi começar uma série de posts rápidos sobre tudo que um Sênior deve saber. Vamos ao primeiro….
Como lidar com dinheiro?
Quando vamos modelar um Objeto ou qualquer outro domínio, sempre imaginamos o tipo de dado antes mesmo de começar a escrever o dado.
Sabemos que nome é String, sobrenome é String, data de nascimento é um Date, data de ativação será um long, ou Timestamp. Podemos até, em algumas linguagens ter dúvida se usamos um Date ou Datetime. Mas tudo isso depende da linguagem escolhida, certo?
Errado!
Tudo depende da forma como o valor é armazenado em bytes. Sim! Você acha que existe um valor inteiro? Ou string? Não, existem bytes! Somente bytes! E esses valores são representados em bytes. Um inteiro por exemplo são 4 bytes alinhados. Assim um inteiro 0 é 00000000 00000000 00000000 00000000. Em Java um short 0 é 00000000 00000000. Fácil? Nem tanto…
Lembra dos conjuntos numéricos da matemática? Pois bem, números inteiros são fáceis, agora e os outros?
Quando eu preciso de um valor não exato, um float por exemplo? Sabe como é armazenado? Usando a notação floating point.
Então qualquer valores de dinheiro devem ser guardados em Float, certo?
Errado!
Vamos olhar bem de perto algumas operações do float ou double.
Entendeu porque 2.01 + 2.01 + 2.01 + 2.01 + 2.001 = 10.040999999999999
? E não 10.041
? 🙄🙄🙄
Float Point precision problem
Sim, esse é um erro bastante conhecido. Você pode pesquisar por ele na internet. Ele aparece quando são feitas várias operações com Floating Point.
Já vi ocorrer em sistemas em produção. Era um sistema de controle de estoque e compras. Havia várias ordem de compras, mas o valor vendido não batia com o caixa. Esse erro se deu em uma conta simple com 5 valores. Agora e se tivessemos 5.000 valores?
Vamos ver… E se somassemos 5.000
vezes 2.01
? Deveria dar 10.050
.
Opa! Tivemos um erro de 0,676
! 😮😮😮😮😮
Solução em Java
Mas vamos com calma. Em Java esse problema foi resolvido com a criação da classe BigDecimal
.
Nenhuma operação monetária deve ser feita com float
ou decimal
em hipotese alguma. Esse valores devem ser lidos como BigDecimal.
Fique Atento
- Se esse valor for instanciado com um
double
oufloat
irá herdar a imprecisão do valor original. - Essa classe é imutável, então fique atento. Se você chamar os metodos, não irá alterar o valor da instância, apenas criar uma nova!
Conclusão
Guarde pra vida toda. Nunca armazene valores monetários em double
ou float
. Não importa a linguagem ou base de dados que você está usando.
Caso não saiba como resolver esse problema. Não se preocupe é normal. Amanhã vai surgir uma linguagem nova ou uma base de dados nova e 99,99999% dos desenvolvedores não sabaerão também. Pesquise no Google.