Sprintf
四舍六入:
value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", 9.824), 64)
fmt.Println(value) //9.82
value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", 9.826), 64)
fmt.Println(value) //9.83
第三位为5且5之后有有效数字,满足五入:
value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", 9.8251), 64)
fmt.Println(value) //9.83
value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", 9.8351), 64)
fmt.Println(value) //9.84
第三位为5且5之后没有有效数字:
网上有人说,第二位为奇数则进位,第二位为偶数则舍去,例如:
value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", 9.825), 64)
fmt.Println(value) //9.82
value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", 9.835), 64)
fmt.Println(value) //9.84
但是:
value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", 9.815), 64)
fmt.Println(value) //9.81 居然舍去了
value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", 9.845), 64)
fmt.Println(value) //9.85 居然进位了
所以,如果想满足正常的四舍五入逻辑,最好不要使用Sprintf处理。
math.Trunc
fmt.Println(math.Trunc(9.815*1e2+0.5)*1e-2) //9.82
fmt.Println(math.Trunc(9.825*1e2+0.5)*1e-2) //9.83
fmt.Println(math.Trunc(9.835*1e2+0.5)*1e-2) //9.84
fmt.Println(math.Trunc(9.845*1e2+0.5)*1e-2) //9.85
以上结果显示符合四舍五入,但是偶尔会出现精度问题:
fmt.Println(math.Trunc(3.3*1e2+0.5)*1e-2) //3.3000000000000003
fmt.Println(math.Trunc(3.3000000000000003*1e2+0.5) * 1e-2) //3.3000000000000003
同样使用Trunc,稍作调整:
n10 := math.Pow10(2)
fmt.Println(math.Trunc((9.815+0.5/n10)*n10) / n10) //9.82
fmt.Println(math.Trunc((9.825+0.5/n10)*n10) / n10) //9.83
fmt.Println(math.Trunc((9.835+0.5/n10)*n10) / n10) //9.84
fmt.Println(math.Trunc((9.845+0.5/n10)*n10) / n10) //9.85
fmt.Println(math.Trunc((3.3+0.5/n10)*n10) / n10) //3.3
fmt.Println(math.Trunc((3.3000000000000003+0.5/n10)*n10) / n10) //3.3
符合四舍五入规则。
以上案例及解决方案转载自:点击链接跳转
但是 Trunc 调整后的方案依旧会出现 精度丢失问题
n10 := math.Pow10(2)
math.Trunc((129.975+0.5/n10)*n10) / n10 //结果为129.97
最终一番查找后的解决方案是 采用 decimal 包,将float64类型转换成 decimal 进行计算,需要自行下载 “github.com/shopspring/decimal”
附上我写的方法
func RetainTwoDecimal(num float64) float64 {
var num2 float64
decimalValue := decimal.NewFromFloat(0)
if num <0 {
decimalValue = decimal.NewFromFloat(num - 0.005)
}else {
decimalValue = decimal.NewFromFloat(num + 0.005)
}
//乘100
decimalValue = decimalValue.Mul(decimal.NewFromInt(100))
res,_ := decimalValue.Float64()
num3 := math.Trunc(res)
decimalValue2 := decimal.NewFromFloat(num3)
//除100
decimalValue2 = decimalValue2.Div(decimal.NewFromInt(100))
num2,_ = decimalValue2.Float64()
return num2
}