Go语言实现原理——浮点数
浮点数
1、概述
在使用二进制在表示小数时,无法准确表示0.1、0.01、0.001,因此能做的就只有提高精度,而定点数由于位数限制,精度无法满足需求,因而采用浮点数表示小数。Go语言中的浮点数遵循IEEE-754
标准。格式如下:
精度 | 符号位 | 指数为 | 小数位 | 偏移量 |
---|---|---|---|---|
单精度(32 Bit) | 1 Bit(31) | 8 Bits (30~23) | 23 Bits (22~00) | 127 |
双精度(64 Bit) | 1 Bit(63) | 11 Bits (62~52) | 52 Bits (51~00) | 1023 |
2、浮点数转换
十进制小数与浮点数的转换方法如下:
点击这里查看:十进制小数与浮点数的转换
3、NaN与Inf
Go语言中,正无穷与负无穷分别用 +Inf
和-Inf
表示,NaN
表示无效的数字
4、浮点数精度
4.1、概念
十进制数转换成二进制,然后再转换成10进制,如果前后一致则没有发生精度损失,否则有精度损失。如下图所示
4.2、浮点数计算时的精度丢失
浮点数在计算时可能产生精度丢失,由于进度限制,所以其在运算过程需要对结果进行四舍五入,比如两个正数做加减法,需要先调整指数变成一样的(这一步会使得小数部分有一部分可能会超出进精度范围,进而造成精度丢失),然后再对小数部分做加法操作。因此,为了尽可能减少精度带来的损失,应该优先进行乘除,最后再进行加减操作
示例代码:
func test() {
var n float64 = 0.123456789999
var m float64 = 0.034567833333
var i float64 = 3.0
// 加法 + 乘法
// 期望的结果: 0.474073869996
// A x ( B + C ) 0.47407386999600004
// A x B + A x C 0.474073869996
fmt.Println(i * (n + m))
fmt.Println(i*n + i*m)
}
5、浮点数的格式化打印
在Go语言中,由于精度的限制而准确表示高精度的浮点数,所以浮点数默认打印的小数部分默认最多8位,如下所示:
示例:
// 示例一
func main() {
var f float32 = 0.333333333333
fmt.Println(f) // 输出:0.33333334,对应的科学计数法表示是 0.33333334 * 10 ^ 0
}
// 示例二
func main() {
var f float32 = 0.00333333333333
fmt.Println(f) // 输出:0.0033333334,对应的科学计数法表示是 0.33333334 * 10 ^ -2
}
6、math/big库
在有些场景下,float64
的精度可能无法满足业务需求,这时就需要使用到math/big
库了,下面给出代码示例:
示例:
func test() {
a := 0.1
b := 0.2
c := a + b
bigA := big.NewFloat(0.1)
bigB := big.NewFloat(0.2)
bigC := big.NewFloat(0)
// 设置bigC的精度,当值为53时,精度与float64相等
bigC.SetPrec(106)
// 加法操作
bigC.Add(bigA, bigB)
fmt.Println(c) // 输出 0.30000000000000004
fmt.Println(bigC) // 输出 0.30000000000000001665334536937735
}