golang精度损失-go decimal解决float精度损失问题实现 整数与小数间的加减乘除
Golang中float精度丢失问题
几乎所有的编程语言都有精度丢失这个问题,这是典型的二进制浮点数精度损失问题,在定长条件下,二进制小数和十进制小数互转可能有精度丢失。
d := 1129.6
fmt.Println((d * 100)) //输出:112959.99999999999
var d float64 = 1129.6
fmt.Println((d * 100)) //输出:112959.99999999999
m1 := 8.2
m2 := 3.8
fmt.Println(m1 - m2) // 期望是4.4,结果打印出了4.399999999999999
上面的运行结果和我们想的完全不一样,下面我们使用decimal解决这个问题
我们假设你需要 整数与小数一起进行运算,或者 整数除以整数 得到小数这种运算,如果你使用了decimal, 那么之后所有的运算你都必须使用decimal,因为通过它计算出来的结果的类型统统为decimal.Decimal,与float64和int无法一起运算。
go decimal使用过程如下:
首先你需要安装 decimal,
运行:go get github.com/shopspring/decimal
在运算开始前,设置你需要的精确的小数位数,自动四舍五入
decimal.DivisionPrecision = 2 // 保留两位小数,如有更多位,则进行四舍五入保留两位小数
加法 Add
2.1 + 3 float和int相加
var num1 float64 = 3.1
var num2 int = 2
d1 := decimal.NewFromFloat(num1).Add(decimal.NewFromFloat(float64(num2)))
// 这里注意了,此时我们使用一个浮点数 加上 一个整数
// 这里num2 是整数,所以我们通过float64()将它强转为小数,然后进行计算即可,
// 如果两个都是小数则无需使用float64()
// 如果是两个整数也都无需使用float64(), 16/4=4, 16/5=3.2 他们的结果都是 decimal.Decimal 类型,可以通过reflect.TypeOf()方法进行测试,
减法 Sub,乘法 Mul, 除法 Div 用法均与上述类似,不再一一列举。 在计算完成后,返回的数据类型为decimal.Decimal,如你需要转换为常见的数据类型 比如,此时test的类型为decimal.Decimal,你需要将起转化为float64
test := decimal.NewFromFloat(16.25).Div(decimal.NewFromFloat(float64(8)))
// 通过Float64() 方法来实现
windLevel, _ := test.Float64()
// 类似的方法还有 String(), 总之decimal提供了很多实用的数据工具,大家需要计算时可以看看文档或者源码
// Round() 可以进行四舍五入
NewFromFloat(5.45).Round(1).String() // output: "5.5"