Sprintf
第三位为4则舍去,第三位为6则进位,四舍六入:
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
符合四舍五入规则。
如果要固定显示两位小数,需转换为string类型,前提是传入的数值,已经做过两位小数处理,否则依旧会有进位问题:
value := strconv.FormatFloat(3, 'f', 2, 64) fmt.Println(value) //3.00 value = strconv.FormatFloat(3.3, 'f', 2, 64) fmt.Println(value) //3.30 value = strconv.FormatFloat(9.815, 'f', 2, 64) fmt.Println(value) //9.81 被舍去 value = strconv.FormatFloat(9.82, 'f', 2, 64) fmt.Println(value) //9.82
公众号:李田路口