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 😉.
Recentemente tive problema com um app flutter el produção. Lá nesse app eu gero um boleto bancário cujo valor vem da multiplicação entre 3 números com 3 casas decimais. A probabilidade desse resultado ser um número inteiro é baixíssima. Nenhum dos meus testes previu essa possibilidade. Resultado: Um dos boletos falhava ao tentar ser aberto no app antes de imprimir na impressora bluetooth. O boleto abria no sistema web mas nao no app. Todos os outros boletos abriam no app, exceto um.
🤣🤣🤣
Deu um trabalho chato de achar o erro mas era exatamente isso. O tipo Double do Dart não aceita receber um número sem casas decimais. Nunca imaginei que esse erro pudesse acontecer pois todas as linguagens que eu já trabalhei aceitam. Um inteiro não aceita um double mas um double deveria aceitar um inteiro. Fica a dica pra quem estiver desenvolvendo app em flutter.
Em java sempre trabalhei com BigDecimal para valores monetários. Float também não é adequado. E há casos que presenciei em sistemas ERP que trabalham com valores monetários com mais de duas casas decimais. Neste caso, usar um inteiro seria um problema.
lembro que o nubank teve um problema com casas decimais por conta do tipo, e dava uns erros em transacoes por causa disso
Obrigado pelo artigo! É sempre importante lembrar que precisão é crucial quando se trata de valores monetários. O uso do tipo decimal é a melhor opção em linguagens que o suportem, mas caso isso não seja possível, o uso do inteiro como alternativa é uma boa opção. É importante evitar o uso do tipo float para esse fim, pois ele pode causar imprecisão nos cálculos.
Boa postagem! Estou ansioso para ler mais sobre esse e outros tópicos relacionados.
Este comentário foi gerado por uma inteligência artificial. Para saber mais, leia esta publicação.