涉及到金额的时候是,使用Decimal而不是float和double 浮点数

发布时间 2023-12-22 22:47:48作者: youxin

decimal库包是用来解决float类型对象之间运算不准确的问题的。
所以,如果你想使用decimal库包,你必须先把float类型对象通过decimal.NewFromFloat()函数转成decimal.Decimal类型,然后再计算,最后还得再转成你所需要的类型。

范例:

复制代码
package main

import "log"

func main() {
    a := 1129.6
    log.Println(a * 100) //输出:112959.99999999999

    var b float64 = 1129.6
    log.Println(b * 100) //输出:112959.99999999999

    m1 := 8.2
    m2 := 3.8
    log.Println(m1 - m2) // 期望是4.4,结果打印出了4.399999999999999
}

// 输出的结果是:
2023/03/16 13:38:24 112959.99999999999
2023/03/16 13:38:24 112959.99999999999
2023/03/16 13:38:24 4.3999999999999995
// 从上面的输出结果看到,数值的精度出现了一定程度的变化,这显然不是我们想要的结果。
复制代码

 

解决:

由于golang中默认是没有decimal类型的,所以要解决上述的问题,需要使用第三方库包decimal decimal.Decimal是一种数据类型

go get github.com/shopspring/decimal

 

使用:

复制代码
package main

import (
    "fmt"
    "log"
    "github.com/shopspring/decimal"
)

func main() {
    var v1 = decimal.NewFromFloat(0.1)  // 声明一个decimal.Decimal类型的变量v1
    var v2 = decimal.NewFromFloat(0.2)  // 声明一个decimal.Decimal类型的变量v2

// 支持从其他数据类型中解析浮点型数据 NewFromString / NewFromFloat32 / NewFromInt() ... // decimal.Decimal类型变量之间的加减乘除 // 所得到的结果也是decimal.Decimal类型 var v3 = v1.Add(v2) // 0.3 var v4 = v1.Sub(v2) // -0.1 var v5 = v1.Mul(v2) // 0.02 var v6 = v1.Div(v2) // 0.5 // 声明一个decimal.Decimal类型的对象 var v7 = decimal.NewFromFloat(3.4625) var data1 = v7.Round(1) // 3.5,保留一位小数,四舍五入的方式 var data2 = v7.Truncate(1) // 3.4,保留一位小数,直接舍弃,直接截断的方式 log.Println(v3, v4, v5, v6) log.Println(data1, data2) // 输出的结果是 0.3 -0.1 0.02 0.5 3.5 3.4 // 最后别忘了还需要转换成你所需要的数据类型 decimal.NewFromFloat(nums).Round(2).Float64() // 四舍五入保留2位小数,最后再转换为float64类型

// 转换成其他数据类型
Float64() // 浮点型
String() // 字符串
  IntPart()  // 返回整数部分
  
}
复制代码

项目实战: 

复制代码
// Fen2Yuan 分转元
func Fen2Yuan[K int | uint](price K) (res float64) {
    d := decimal.New(1, 2)
    res, _ = decimal.NewFromInt(int64(float64(price))).DivRound(d, 2).Float64()
    return
}

// Yuan2Fen 元转分
func Yuan2Fen(price float32) (yuan int64) {
    p := decimal.NewFromFloat32(price)
    yuan = p.Mul(decimal.NewFromInt(100)).IntPart()
    return
}
复制代码

 

浮点精度(float、double)运算不精确的原因

参考:

https://www.cnblogs.com/xingxia/p/golang_decimal.html

https://www.jianshu.com/p/0c2c5ead2357