SimpleDao
处理float类型不丢失精度
2021-08-15, 访问数: 1196

问题

在处理金额等数字时,需要处理小数。如果在前端页面使用float类型传递的话,会丢失精度,会造成影响。
而且通常MySQL之类的db也没有很好的方法处理小数。

需求1

  • 需要找一个方法处理小数问题,并且尽量不丢失精度

方案

设计API的时候,前端直接传递用户输入的数字,类型为string,比如“1.23456789”
后端直接处理这个字符串,保存到db的时候,可以考虑:

  • 直接保存字符串
    • 优点:简单,容易理解
    • 缺点:不利于使用数据库搜索
  • 转换成一定倍率的int64,然后保存,例如:需求是保留5位小数,那么转换成123456,然后保存
    • 优点:可以使用数据库搜索
    • 缺点:输入输出需要转换,而且每次操作都不能忘记转换,比较繁琐

需求2

  • 处理超过int64的加减乘除

方案

输入输出都是字符串,实现加减乘除,然后做除法时能自定义精度

golang 例子

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/lvshuchengyin/gobignumber"
  5. )
  6. const (
  7. DecimalPlaces = 5
  8. )
  9. func main() {
  10. floatString := "123.456789"
  11. int64WithPricision := int64(0)
  12. int64WithPricision, err := gobignumber.FloatStringToInt64(floatString, DecimalPlaces)
  13. if err != nil {
  14. fmt.Println("FloatStringToInt64 err", err.Error())
  15. return
  16. }
  17. fmt.Printf("FloatStringToInt64, floatString:%v, int64WithPricision:%v\n", floatString, int64WithPricision)
  18. floatString, err = gobignumber.Int64ToFloatString(int64WithPricision, DecimalPlaces)
  19. if err != nil {
  20. fmt.Println("Int64ToFloatString err", err.Error())
  21. return
  22. }
  23. fmt.Printf("Int64ToFloatString, int64WithPricision:%v, floatString:%v\n", int64WithPricision, floatString)
  24. {
  25. sbn, _ := gobignumber.NewBigNumberFromString("-0.00034567")
  26. sbn2, _ := gobignumber.NewBigNumberFromString("-12.345678")
  27. sbn3 := sbn.Add(sbn2)
  28. fmt.Println("Add", sbn, sbn2, sbn3)
  29. }
  30. {
  31. sbn, _ := gobignumber.NewBigNumberFromString("-0.00034567")
  32. sbn2, _ := gobignumber.NewBigNumberFromString("-12.345678")
  33. sbn3 := sbn.Sub(sbn2)
  34. fmt.Println("Sub", sbn, sbn2, sbn3)
  35. }
  36. {
  37. sbn, _ := gobignumber.NewBigNumberFromString("-0.00034567")
  38. sbn2, _ := gobignumber.NewBigNumberFromString("-12.345678")
  39. sbn3 := sbn.Mul(sbn2)
  40. fmt.Println("Mul", sbn, sbn2, sbn3)
  41. }
  42. {
  43. sbn, _ := gobignumber.NewBigNumberFromString("-0.00034567")
  44. sbn2, _ := gobignumber.NewBigNumberFromString("-12.345678")
  45. sbn3 := sbn.Quo(sbn2, 10)
  46. fmt.Println("Quo", sbn, sbn2, sbn3)
  47. }
  48. }

输出

  1. FloatStringToInt64, floatString:123.456789, int64WithPricision:12345678
  2. Int64ToFloatString, int64WithPricision:12345678, floatString:123.45678
  3. Add -0.00034567 -12.345678 -12.34602367
  4. Sub -0.00034567 -12.345678 12.34533233
  5. Mul -0.00034567 -12.345678 0.00426753051426
  6. Quo -0.00034567 -12.345678 0.0000279992