Qual tipo de dados devemos usar para valores monetários
Entendendo o problema
Estive lendo artigos e pensei em passar essa informação por aqui, esse post está aberto a incrementações do assunto e correção de erros.
No geral, antes de mais nada, qual tipo você usaria? O mais lógico a se pensar, seria o float, correto? Mas infelizmente, ele talvez seja a pior das opções, vamos falar um pouco do porque disso.
O float da maioria das linguagens é baseado no IEEE-754, onde há o cálculo do expoente e de sua mantissa, veja essa imagem de exemplo:
Nesse modelo, quanto mais próximo o valor estiver do 0, mais impreciso ele será, entendeu agora o famoso problema do 0.1 + 0.2 = 0.3000000...4
? Então, vamos lembrar que estariamos mexendo com dinheiro, talvez você não se importasse de perder alguns centavos, mas para um banco ou corretora, isso é uma perda gigantesca, tendo em vista a quantidade de dinheiro movimentado.
Então devemos usar o que?
A maioria das linguagens não possuem suporte ao tipo decimal como a maioria dos banco de dados, onde costumamos por decimal(15,2). No geral, esse tipo é mais recomendado por conta de sua precisão, tendo menos chances de falhas do que Float e Double.
Mas, caso sua linguagem não possua Decimal e você não pretenda usar nenhuma biblioteca para resolver esse problema, então, lhe convido a usar integer.
Inteiro? Como assim, e os centavos?
Toda linguagem suporta o tipo int (tirando o JS que usa Number, mas tem como tratar).
Na verdade você irá contar o valor monetário a partir dos centavos, dentro do inteiro, ou seja, 1,50 seria 150. A ideia é que o backend não precisa se importar com o que é mostrado para o usuário, então salvar o dado como inteiro gera menos risco de perda de valores.
Quando for necessário exibir o valor para o usuário, basta dividir o valor por 100, assim, criando novamente as 2 casas decimais para os centavos. Sem gerar o problema citado anteriormente.
30 / 100 = 0.3
e não 0.3000...4
Conclusão
No geral, são casos e casos, há pessoas que usam String e convertem para inteiro quando desejam realizar algum cálculo, isso entra no assunto "devemos usar string em números, quando não calculamos os mesmos, como CPF", mas isso é outro tópico 😉.