Golang四舍五入保留兩位小數


 

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

符合四舍五入規則。

如果要固定顯示兩位小數,需轉換為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

內容修改

錯誤示例:

n10 := math.Pow10(2) fmt.Println(math.Trunc((129.975+0.5/n10)*n10) / n10) // 129.97 fmt.Println(math.Trunc((34423.125+0.5/n10)*n10) / n10) // 34423.12

代碼修改:

package main import ( "fmt" "github.com/shopspring/decimal" ) func main() { v1, _ := decimal.NewFromFloat(9.824).Round(2).Float64() v2, _ := decimal.NewFromFloat(9.826).Round(2).Float64() v3, _ := decimal.NewFromFloat(9.8251).Round(2).Float64() fmt.Println(v1, v2, v3) v4, _ := decimal.NewFromFloat(9.815).Round(2).Float64() v5, _ := decimal.NewFromFloat(9.825).Round(2).Float64() v6, _ := decimal.NewFromFloat(9.835).Round(2).Float64() v7, _ := decimal.NewFromFloat(9.845).Round(2).Float64() fmt.Println(v4, v5, v6, v7) v8, _ := decimal.NewFromFloat(3.3).Round(2).Float64() v9, _ := decimal.NewFromFloat(3.3000000000000003).Round(2).Float64() v10, _ := decimal.NewFromFloat(3).Round(2).Float64() fmt.Println(v8, v9, v10) v11, _ := decimal.NewFromFloat(129.975).Round(2).Float64() v12, _ := decimal.NewFromFloat(34423.125).Round(2).Float64() fmt.Println(v11, v12) }

結果如下:

9.82 9.83 9.83 9.82 9.83 9.84 9.85 3.3 3.3 3 129.98 34423.13

公眾號:李田路口


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM