在寫程式的過程, 多多少少會遇到需要複雜處理的狀況, Go的優點是很多使用情境已經有前人幫忙整理成套件了, 只要go get
下來就可以馬上使用, 這實在是省下了不少時間。其中一個就是浮點數處理。
Go的浮點數使用的是IEEE-754標準儲存浮點數, wiki有詳細的介紹, 主要是因為IEEE-754是採用二進位的方式運算, 在運算的過程當中會產生一個無限循環數, 經過四捨五入之後就出現了偏差值。這個坑很容易就會踩進去了, 算是寫Go的過程多數人都會體驗一回的坑。
為了修正這個浮點數問題, 在浮點數計算時我們會使用套件shopspring/decimal
先來看一下為處理前的狀況, 數學計算時0.3
+0.6
=0.9
,
但是Go程式跑起來卻不是這樣, Go裡面針對浮點數的部分有float32
跟float64
, 來跑跑看結果
func main() {
var (
b1 float32
b2 float32
c1 float64
c2 float64
)
b1 = 0.3
c1 = 0.3
b2 = 0.6
c2 = 0.6
b := b1 + b2
fmt.Println("b:", b)
c := c1 + c2
fmt.Println("c:", c)
}
結果
b: 0.90000004
c: 0.8999999999999999
是不是讓人懷疑人生.....
這時候把問題丟給Google, Google就會跳出前人的經驗, 找到推薦的浮點數處理套件之後, 再來跑一次
func main() {
var (
b1 float32
b2 float32
c1 float64
c2 float64
)
b1 = 0.3
c1 = 0.3
b2 = 0.6
c2 = 0.6
b := b1 + b2
fmt.Println("b:", b)
bb, _ := decimal.NewFromFloat32(b1).Add(decimal.NewFromFloat32(b2)).Value()
fmt.Println("bb:", bb)
c := c1 + c2
fmt.Println("c:", c)
cc, _ := decimal.NewFromFloat(c1).Add(decimal.NewFromFloat(c2)).Float64()
fmt.Println("cc:", cc)
}
可以看到使用套件的運算結果有符合預期的狀況。
b: 0.90000004
bb: 0.9
c: 0.8999999999999999
cc: 0.9
參考資料