你有没有好奇过,电脑是怎么理解我们输入的小数的?比如你打0.15,它其实不是直接存成“零点一五”,而是转化成一串二进制代码。这背后的关键就是IEEE 754标准。别被名字吓到,其实只要几步,你自己也能算出来。
先搞清楚IEEE 754是啥
IEEE 754是一种规定浮点数在计算机中怎么存储的标准。最常见的有32位单精度格式,由三部分组成:1位符号位、8位指数位、23位尾数位。咱们就拿这个来举例。
举个例子:把 -6.625 转成 IEEE 754 单精度格式
第一步,确定符号。负数,所以符号位是1。正数就是0。
第二步,把整数部分和小数部分分别转成二进制。
6 的二进制是 110。0.625 怎么转?用乘2取整法:
0.625 × 2 = 1.25 → 取1,剩下0.25
0.25 × 2 = 0.5 → 取0,剩下0.5
0.5 × 2 = 1.0 → 取1,结束
所以0.625的二进制是0.101。合起来,6.625 就是 110.101。
第三步,规格化。把二进制数写成 1.xxxx × 2^n 的形式。
110.101 = 1.10101 × 2²(小数点左移两位)
这时候,1. 后面的部分就是尾数:10101。补够23位,后面加0:
10101000000000000000000
第四步,算指数。原来的指数是2,但IEEE 754要求加上一个偏移量127,所以 2 + 127 = 129。
129 的二进制是 10000001。
第五步,拼起来。
符号位:1
指数位:10000001
尾数位:10101000000000000000000
连起来就是:1 10000001 10101000000000000000000
如果按字节分组,就是:1100 0000 1101 0100 0000 0000 0000 0000,对应十六进制 C0D40000。你在调试程序时看到这种数,可能就是它。
平时用Python的话,也可以简单验证:
import struct
# 把浮点数打包成4字节,再转成无符号整数
struct.unpack('<I', struct.pack('<f', -6.625))[0]
结果会是 3237226496,转成十六进制正好是0xC0D40000,对上了。
下次看到浮点数精度问题,比如0.1 + 0.2 不等于0.3,你就知道,其实是这些小数转二进制时根本存不准,IEEE 754尽力了,但也有限。