一、整数在内存中的存储
- 整数的2进制表示方法有:原码、反码、补码 三种。三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位最高位的⼀位是被当做符号位,剩余的都是数值位。
- 正整数的原码、反码、补码都相同。
- 负整数的三种表示方法各不相同。
- 原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码。
- 反码:将原码的符号位不变,其他位一次按位取反就可以得到反码。
- 补码:反码 +1 就得到补码。
二、浮点数在内存中的存储
- 常见的浮点类型包括:float、double、long double.
- 浮点数表示的范围:float.h 中定义。
浮点数在计算机内部的表示方法:
根据国际标准IEEE(电气和电子工程协会) 754,任意⼀个二进制浮点数V可以表示成下面这种形式:
V = (-1)^S * M * 2^E
其中, (-1)^S表示符号位,M是大于等于1,小于2;
2^E表示指数位。
- IEEE 754规定:
- 对于32位的浮点数,最高的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
- 对于64位的浮点数,最高的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M
浮点数取的过程
指数E从内存中取出可分为以下三种情况:
- E不全为0或不全为1
这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将有效
数字M前加上第一位的1。
比如:0.5 的二进制形式为0.1,由于规定正数部分必须为1,即将⼩数点右移1位,则为1.0*2^(-1),其
阶码为-1+127(中间值)=126,表示为01111110,而尾数1.0去掉整数部分为0,补齐0到23位00000000000000000000000,则其二进制表示形式为: 0 01111110 00000000000000000000000
- E全为0
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第⼀位的1,而是还
原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
- E全为1
这时,如果有效数字M全为0,表示无穷大(正负取决于符号位s)
三、练习
下面这段代码的输出结果为什么呢?
#include <stdio.h>
int main()
{
int n = 9;
float *pFloat = (float *)&n;
printf("n的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
*pFloat = 9.0;
printf("num的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
return 0;
}
输出结果为:
n的值为:9
*pFloat的值为:0.000000
num的值为:1091567616
*pFloat的值为:9.000000
结果分析:
1)问题来了,为什么 9 还原成浮点数,就成了 0.000000 ?
- 那是因为 9以整型的形式存储在内存中,得到如下二进制序列:
0000 0000 0000 0000 0000 0000 0000 1001- 首先,将 9 的二进制序列按照浮点数的形式拆分,得到第⼀位符号位s=0,后面8位的指数:E=00000000。最后23位的有效数字 M=000 0000 0000 0000 0000 1001。
- 由于指数E全为0,所以符合E为全0的情况。因此,浮点数V就写成:
V=(-1)^0 × 0.00000000000000000001001×2^(-126) = 1.001×2^(-146)- 显然,V是⼀个很小的接近于0的正数,所以用十进制小数表示就是 0.000000。
2)浮点数9.0,为什么整数打印是 1091567616 ?
- 首先,浮点数9.0 等于⼆进制的1001.0,即换算成科学计数法是:1.001×2^3
所以: 9.0 = (−1)^0 ∗ (1.001) ∗ 2^3 ,- 那么,第⼀位的符号位S=0,有效数字M等于001后⾯再加20个0,凑满23位,指数E等于 3+127=130,即 10000010
- 所以,写成二进制形式,应该是S+E+M,即:
0 10000010 001 0000 0000 0000 0000 0000- 这个32位的二进制数,被当做整数来解析的时候,就是整数在内存中的补码,原码正是 1091567616