- float32(单精度类型,占据4个字节 byte,32个二进制位 bit)
- float64(双精度类型,占据8个字节 byte,64个二进制位 bit)

转换成以 2 为底的科学计数法:

从上面我们可以观察到,对于任何数来说,表示成二进制科学计数法后,都成以转换成 1.xxx(尾数) * 2 的 n 次方(指数)。
这里需要注意到的一点是,比如上图中的十进制小数0.6,表示成二进制后变成了以1001循环的无限循环小数。
这便是浮点数有精度问题的根源之一,在代码中声明的小数0.6,计算机底层其实是无法精确存储那个无限循环的二进制数的。
只能存入一个零舍一入(类似于十进制的四舍五入)后的近似值。
对于小于0的负数来说,则可以表示成 -1.xxx(尾数) * 2 的 n 次方(指数)
所以内存中要存储这个小数,则可以拆解成三个部分来存储:
- 正负号
- 指数
- 尾数
如图所示:

具体存储方式如上图所示。最高位有1bit存储正负号,然后指数部分占据8bits(4字节)或11bits(8字节),其余部分全都用来存储尾数部分。
对于指数部分,这里存储的结果是实际的指数加上偏移量之后的结果。
这里设置偏移量,是为了让指数部分不出现负数,全都为大于等于0的正整数。
尾数部分的存储,因为二进制的科学计数法,小数点前一定是1开头,因此我们尾数只需要存储小数点后面的部分即可。
接下来依然是举例说明,4字节浮点数(Golang 中的 float32):

再来观察一个 8 字节浮点数(Golang 中的 float64)的例子:

偏移量:
- 4字节浮点数的偏移量为 127
- 8字节浮点数的偏移量为 1023
加上偏移量可以统一地把正数和负数统一转化成无符号的证书,方便进行比较,举例说明:
4字节浮点数的指数部分为 -7 ,则通常表示为 10000111 1为符号位,代表它是一个负数。
7 表示为 00000111 0为符号位,代表它是一个负数。
如果把 7 和 +7 统一加上偏移量 127
那么 7 就变成 134 ,二进制表示为 10000110
-7变成 120 ,二进制表示为 01111000
两者进行比较大小的时候,计算机便无需比较两者的符号位。
小结
计算机在存储小数的时候,分为两种类型:
- 单精度类型(占据32个二进制位,4个字节)
- 双精度类型(占据64个二进制位,8个字节)
- 双精度类型比单精度类型更能精确地表示一个小数,但是占用的内存空间也比较大。
- 计算机表示一个小数时,先把这个小数转化成以2为底的科学计数法。
- 然后再根据这个数字,把小数拆解成符号位、指数、尾数,存储进内存当中。
