一、整数存储
整数在内存中是以补码的形式进行存储,先写出一个数的原码
所谓原码就是直接表示这个数的大小
比如:-1原码(x86系统):10000000 00000000 00000000 00000001
反码:11111111 11111111 11111111 11111110
补码: 11111111 11111111 11111111 11111111
三种表示方法均有符号位+数值位,符号位用0表示正,1表示负,最高一位被当做符号位,其余为数值位。
最后从运行窗口显示内容,也是要将补码转换成原码进行显示的,
但计算机内的存储以及运算都是用补码进行的。
有符号整数:
正数的原码、反码、补码均相同;
负数的反码等于原码的符号位不变,其余数值位取反;补码等于反码再加1,;
同样已知一个负数的补码,可通过对补码取反再加1来求得原码。
无符号整数:
不存在符号位,均为数值位,原码、反码、补码均相同
为什么数据在内存中存放的是补码?
原因在于,使用补码可以将符号位和数值位统一处理,同时,加法和减法也可以统一处理(cpu只有加法器),补码与原码可以相互转换,运算过程是相同的,不需要额外的硬件电路。
二、浮点数的存储?
二进制浮点数V可以表示成下面的形式:
V = (-1)^s * M * 2^E
- (-1)^s表示符号位,当S=0;表示正数,当s=1,表示负数;
- M表示有效数字,1<=M<2;
- 2^E表示指数位;
- 十进制5.0,写成二进制为101.0,1.01*2^2;S=0,E=2,M=1.01
- IEEE754进行规定:
- 对于32位的浮点数,最高的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M;
- 对于64位的浮点数,最高的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M;
符号位1bit | 指数位占8bit | 数值位占23bit |
符号位1bit | 指数位占8bit | 数值位占23bit | |||||||||||||||||||||||||||||
浮点数存储的过程
M的存储
对于M,要将M写成1.XXXXXX的形式,是1<=M<2;其中XXXXXX表示小数部分。
IEEE754标准规定,保存M时,默认这个数的第一位总是1,于是可以舍去,只保存XXXXXX部分,比如在保存1.01时只保存01,等到读取时,再自动把第一位的1加上去,可以节省一位有效数字,相当于能保存小数点后23位,再加上小数点前一位1,一共可保存24位有效数字。
E的存储
E为一个无符号的整数,如果为8位,它取值范围为0~255;如果E为11位,它的取值为0~2047.但是科学计数法是可以出现负数的,所以IEEE754规定,存入内存时E的真实值必须再加上一个中间数,对于8位E,这个中间数是127;对于11位的E,这个中间数是1023。比如2^3,保存在32位浮点数时为3+127=130,即10000010
E不全为0或者1
即指数E的值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1
例如对于:
0 01111110 00000000000000000000000
指数E=126-127=-1,M=1.0,S=0;
结果为:(-1)^0*1.0*2^(-1)=0.5;
E全为0
指数E=1-127或者(1-1023),有效数字M不再加上第一位1,而是还原成0.XXXXXX的小数,这样是为了表示±0,以及接近于0很小的数字。
0 00000000 00100000000000000000000
E全为1
如果有效数字M全为0,表示±无穷大,正负取决于S
0 11111111 00000000000000000000000
练习题
int main() { int n = 9; float* pf = (float*)&n; printf("%d %f\n", n, *pf); *pf = 9.0; printf("%d %f\n", n, *pf); return 0; }
读这可自行进行验证,检验学习的效果,尝试写出9和9.0在内存中分别是怎样存储的