day 24 - 失控的浮点数, decimal套件介绍

在写程序的过程, 多多少少会遇到需要复杂处理的状况, 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

参考资料


<<:  [DAY18]旋转木马(01)

>>:  [13th][Day24] kubernetes 是什麽

Day10-流量限制(五)

前言 前几天终於把限制请求「数量」的部分讲完了,但光是限制数量是不够的,最好还能限制每个请求的大小,...

Eloquent ORM - 一对一关联

Eloquent 可以在 Model 之间建立关联查询,这样可以藉由这些关联快速查询出所需的资料。 ...

[Day 07] 前6天到底在瞎忙什麽? 当然是要打包成微服务阿! - .Net Core 3.1小试身手与简介

前几天做了那麽多准备工作,当然就是为了在之後能够很顺利的串接永丰金流API的其他服务 其实一开始收到...

Day 03 - 环境安装(下) JDK & Spring Tool Suite

环境安装的最後一个环节,就是安装我们的开发工具,本篇教学使用Spring Tool Suite (S...

Day 10 Self-attention(四) 要如何平行运算?

Self-attention 昨天讲到要怎麽用input的四个vector,a1、a2、a3、a4来...