一、载入decimal包
go get github.com/shopspring/decimal
二、结构定义
注意:前端传参转成包含decimal的结构时,建议使用 json.Unmarshal(xx, &buyGoods{})
import (
"github.com/shopspring/decimal"
)
// 购买商品
type buyGoods struct {
Num int `json:"num"` // 数量',
Price decimal.Decimal `json:"price"` // 单价'
}
三、逻辑使用
// 先将int 转成string 再转成 decimal类型去运算
sellNum, _ := decimal.NewFromString(strconv.Itoa(e.Num))
totalMoney := MulDecimal(e.Price, sellNum)
四、对应decimal的运算方法
import "github.com/shopspring/decimal"
// 主要用于处理浮点数据精度
// 加法
func AddDecimal(d1 decimal.Decimal, d2 decimal.Decimal) decimal.Decimal {
return d1.Add(d2)
}
// 减法
func SubDecimal(d1 decimal.Decimal, d2 decimal.Decimal) decimal.Decimal {
return d1.Sub(d2)
}
// 乘法
func MulDecimal(d1 decimal.Decimal, d2 decimal.Decimal) decimal.Decimal {
return d1.Mul(d2)
}
// 除法
func DivDecimal(d1 decimal.Decimal, d2 decimal.Decimal) decimal.Decimal {
return d1.Div(d2)
}
// int
func IntDecimal(d decimal.Decimal) int64 {
return d.IntPart()
}
// float
func FloatDecimal(d decimal.Decimal) float64 {
f, exact := d.Float64()
if !exact {
return f
}
return 0
}
实例2
package main
import (
"fmt"
"github.com/shopspring/decimal"
)
func main() {
a := decimal.NewFromFloat(1136.1)
b := a.Mul(decimal.NewFromInt(100))
fmt.Println(b) // 正确输出 113610
c := decimal.NewFromFloat(1.7)
fmt.Println(a.Sub(c)) // 正确输出 1134.4
fmt.Println(b.Sub(c)) // 正确输出 113608.3
}
之后对于各种数字的计算就会变得得心应手:
package main
import (
"fmt"
"github.com/shopspring/decimal"
)
func main() {
a := decimal.NewFromFloat(1.52)
b := decimal.NewFromFloat(0.02)
// 加减乘除运算
c := a.Add(b) // 1.52 + 0.02 = 1.54
d := a.Sub(b) // 1.52 - 0.02 = 1.5
e := a.Mul(b) // 1.52 * 0.02 = 0.0304
f := a.Div(b) // 1.52 / 0.02 = 76
fmt.Println(a, b, c, d, e, f)
// 对于保留小数的处理
pi := decimal.NewFromFloat(3.1415926535897932384626)
pi1 := pi.Round(3) // 对pi值四舍五入保留3位小数
fmt.Println(pi1) // 3.142
pi2 := pi.Truncate(3) // 对pi值保留3位小数之后直接舍弃
fmt.Println(pi2) // 3.141
}
对于数值变量类型的转换也游刃有余了:
var a float64
var b = "69.77"
var c int64
d, err := decimal.NewFromString(b)
if err != nil {
fmt.Println(err.Error())
}
a, _ = d.Float64()
fmt.Println(a) // float64 69.77
c = d.IntPart() // 舍去小数取整
fmt.Println(c) // int64 69
b = decimal.NewFromInt(c).String()
fmt.Println(b) // string 69
c = d.Round(0).IntPart() // 不保留小数四舍五入取整
fmt.Println(c) // int64 70
这里列出一些常用的方法:
n1 := decimal.NewFromFloat(-1.23)
n2 := decimal.NewFromInt(3)
n3, _ := decimal.NewFromString("0")
n1.Abs() // 取绝对值
n1.Equal(n2) // n1 是否与 n2 相等
n1.LessThan(n2) // n1 是否小于 n2
n1.LessThanOrEqual(n2) // n1 是否小于或等于 n2
n1.GreaterThan(n2) // n1 是否大于 n2
n1.GreaterThanOrEqual(n2) // n1 是否大于或等于 n2
n3.IsZero() // n3 是否为0
总结
Decimal库会给我们项目中用到数值计算时提供极大的便利和安全性。
最后需要注意的一点是,使用Decimal库的变量数据类型全部为decimal.Decimal,同样decimal.Decimal也可以作为声明变量时的数据类型使用,所以记得在最后做变量赋值时转换为需要的数据类型。
package main
import (
"fmt"
"github.com/shopspring/decimal"
"reflect"
)
func main() {
n1 := decimal.NewFromFloat(3.14)
var n2 string
var n3 float64
var n4 int64
var n5 decimal.Decimal
n2 = n1.String()
n3, _ = n1.Float64()
n4 = n1.IntPart()
fmt.Printf("n1 = %v, type = %v\n", n1, reflect.TypeOf(n1).String())
// n1 = 3.14, type = decimal.Decimal
fmt.Printf("n2 = %v, type = %v\n", n2, reflect.TypeOf(n2).String())
// n2 = 3.14, type = string
fmt.Printf("n3 = %v, type = %v\n", n3, reflect.TypeOf(n3).String())
// n3 = 3.14, type = float64
fmt.Printf("n4 = %v, type = %v\n", n4, reflect.TypeOf(n4).String())
// n4 = 3, type = int64
fmt.Printf("n5 = %v, type = %v\n", n5, reflect.TypeOf(n5).String())
// n5 = 0, type = decimal.Decimal
}