前言
本文主要包含
- 浮点数存储结构
- 浮点数运算(对阶,舍入)
一、 从一段golang代码说起
func main() {
var a float32 = 0.1
var b float32 = 0.2
var c float32 = 0.3
fmt.Println( a + b = c)
// true
var aa float64 = 0.1
var bb float64 = 0.2
var cc float64 = 0.3
fmt.Println( aa + bb = cc)
// false
}
是否会疑问,32位0.1+0.2等于0.3,而64位的不等于
二、浮点数存储理论知识

- ^s表示符号位,当s=0,V为正数;当s=1,V为负数。
- M表示有效数字,大于等于1,小于2。
- 2^E表示指数位
三、验证float32 0.1+0.2 == 0.3
3.1 将0.1 0.2 0.3小数转为二进制
方法为乘2取整,示例:
2 * 0.1 = 0.2 整数位0
2 * 0.2 = 0.4 整数位0
2 * 0.4 = 0.8 整数位0
2 * 0.8 = 1.6 整数位1
2 * 0.6 = 1.2 整数位1
2 * 0.2 = 0.4 整数位0
2 * 0.4 = 0.8 整数位0
2 * 0.8 = 1.6 整数位1
⋯⋯
如上 0.1的二进制为
0.000110011001100110011001101
转为指数形式
- 0.1
1.10011001100110011001101 × 2⁻⁴ - 0.2
1.10011001100110011001101 × 2⁻³ - 0.3
1.00110011001100110011010 × 2⁻²
3.2 计算0.1+0.2
- 对阶
由于指数位数不同,需要先对阶,对阶法则为:
小阶像大阶看齐,小阶尾数右移
- 0.1对阶后
0.110011001100110011001101 × 2⁻³ - 0.1对阶后,尾数已经超过23位,需要舍入,结果为
0.11001100110011001100111 × 2⁻³
- 加法运算(此处加法运算可以使用Windows自带的计算器)
0.11001100110011001100111 × 2⁻³ +
1.10011001100110011001101 × 2⁻³
结果为
10.01100110011001100110100 × 2⁻³
右移一位
1.001100110011001100110100 × 2⁻²
进行舍入,相加结果为
1.00110011001100110011010 × 2⁻²
此时再和前面0.2对比,是否相等
3.3 结论
32位0.1+0.2结果和0.2存储是一样的,故能相等
四、验证float64 0.1+0.2 == 0.3
留待读者自己做