整数在内存里直来直去,可小数(浮点数)就要「精明」得多——它住的地方,和整数完全是两套规则。
先看一个会让人愣住的实验:
int n = 9;
float* pFloat = (float*)&n;
printf("%d\n", n); // 9
printf("%f\n", *pFloat); // 0.000000 —— 同一个二进制却读不出 9
*pFloat = 9.0;
printf("%d\n", n); // 一个奇怪的大数
printf("%f\n", *pFloat); // 9.000000
结论跃然纸上:浮点数的存储方式和整数不一样!它遵循国际标准 IEEE 754。
一个万能公式:S + M + E
任意一个二进制浮点数 V 都可以写成:
V = (-1)^S × M × 2^E
其中 S 是符号位,M 是有效数字,E 是指数。存浮点数,其实就是存这三样东西的值。
拿十进制的 5.0 举例,先转成二进制 101.0,再写成科学计数法 1.01 × 2^2,于是 S=0, M=1.01, E=2。
float 和 double 的"户型"
float (32 位): 1 位 S | 8 位 E | 23 位 M
double (64 位): 1 位 S | 11 位 E | 52 位 M
存进去的三个小心机
- M 省略第一位的 1:因为
1 ≤ M < 2,总可以写成1.xxx,那个整数位的 1 就默认省略,省下一位给精度。 - E 要加中间数:科学计数法的指数可能是负数,存的时候要加上一个偏移量——8 位 E 加
127,11 位 E 加1023。
比如 2^10 的指数是 10,存成 float 时就是 10 + 127 = 137。
来看一个完整的例子,9.5f:
9.5 → 二进制 1001.1 → 1.0011 × 2^3
S = 0
E = 3 + 127 = 130 → 二进制 10000010
M = 0011(省掉开头 1,后面补零)
拼起来:0 | 10000010 | 00110000000000000000000
取出来的三种情况
E 不全为 0 也不全为 1(常规):真实指数 = 存储值 − 127(或 1023),M 前面补回第一位 1。
E 全为 0:表示 ±0 或非常接近 0 的数,M 还原成 0.xxx,指数为 1 − 127。
E 全为 1:若 M 全 0,表示 ±∞(正负看符号位)。
✿ 摘要
- 浮点数遵循 IEEE 754,与整数的存储方式完全不同。
- 核心公式:
V = (-1)^S × M × 2^E。 - float 是 1+8+23 位,double 是 1+11+52 位。
- 存 M 时省略开头的 1,存 E 时要加中间数(127 / 1023)。
- 取出分「常规、E 全 0、E 全 1」三种情况,分别对应普通数、接近 0 的数、无穷大。
愿当下的花如你所见般美丽
评论交流
欢迎留下你的想法