iT邦幫忙

2021 iThome 鐵人賽

DAY 24
1

在寫程式的過程, 多多少少會遇到需要複雜處理的狀況, Go的優點是很多使用情境已經有前人幫忙整理成套件了, 只要go get 下來就可以馬上使用, 這實在是省下了不少時間。其中一個就是浮點數處理。
Go的浮點數使用的是IEEE-754標準儲存浮點數, wiki有詳細的介紹, 主要是因為IEEE-754是採用二進位的方式運算, 在運算的過程當中會產生一個無限循環數, 經過四捨五入之後就出現了偏差值。這個坑很容易就會踩進去了, 算是寫Go的過程多數人都會體驗一回的坑。
為了修正這個浮點數問題, 在浮點數計算時我們會使用套件shopspring/decimal

先來看一下為處理前的狀況, 數學計算時
0.3+0.6=0.9,

但是Go程式跑起來卻不是這樣, Go裡面針對浮點數的部分有float32float64, 來跑跑看結果

  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

是不是讓人懷疑人生...../images/emoticon/emoticon19.gif

這時候把問題丟給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

參考資料


上一篇
day 23 - 取號機 AUTO_INCREMENT(MYSQL) > INCR(Redis) > snowflake演算法
下一篇
day 25 - 第一手消息 telegram API
系列文
Let's Go! 解剖Go server開發到部署的過程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言