![f3bf2718e65b3121debb97b73876a577.png](https://i-blog.csdnimg.cn/blog_migrate/c12280ed3780512a01d3f853706bc3e4.jpeg)
ok,这里先说明一下,假设是在32位的机器上,int是32位。而float使用的是IEEE 754标准的单精度浮点数格式也是占用32位。
这时候float和int都是占用32位,占用同样的空间,但float范围是更大的,那我们为啥还要int呢?为啥不节省空间,只用float?我们来一探究竟!他们在计算机的大脑里是如何记忆的?
1、int对32个坑是如何使用的?
(实名吐槽知乎,居然没有表格。。。)
int类型的使用方法,大多学过计算机的,应该都是非常清楚的。二进制存储即可。
例1:请写出165(10进制)使用32位int型存储在计算机中的形式。
10进制转换为2进制,我个人喜欢先转为16进制,再写成2进制。
如下:
那么165在32位int型中是这样存储的(中间的0,我省略了):
![cbec11518c8d30917ec81a3ea8335822.png](https://i-blog.csdnimg.cn/blog_migrate/4df7c9bbf68eac7ecc4fee14f3fc67d7.png)
非常简单明了,好理解。把10进制转换2进制,直接存进去就ok,前面空位补0。
例2:请写出-165(10进制)使用32位int型存储在计算机中的形式。
这是一个负数,按照惯例int型首位为符号位。0表示在正数,1表示负数。
如下:
但在计算机中,负数存储的是补码,不是原码。
他们之间按照如下转换:
原码:1000 0000 1010 0101
反码:1111 1111 0101 1010 (除了符号位,其它取反)
补码:1111 1111 0101 1011 (在反码的基础上加1即可)
那么-165在32位int型中是这样存储的(中间的1,我省略了):
![445b5be73b3fdbf21a22d670c5a47729.png](https://i-blog.csdnimg.cn/blog_migrate/ab8f903121ff0587e2c441da6bc10f6e.png)
比正数复杂了一点,但是还是可以很容易算出来的。
问题来了?为啥负数要用补码?这不是挑事吗?原码不好吗?
![888390bfea9ce1f948768dbb47c1d9a0.png](https://i-blog.csdnimg.cn/blog_migrate/a401c251d114b5f65c81aef6031a6094.jpeg)
原因之一在于,我们计算:
如果使用原码进行计算,需要单独把符号位拿出来,再做减法运算,而把符号位区分出来是需要额外的硬件电路支撑的,这很不方便。
如果使用补码,如下所示(这里按照16位进行举例):
0000 0000 1010 0101 + 1111 1111 0101 1011=0000 0000 0000 0000;
使用补码参与运算后,无需再管符号位,可以让符号位直接参与运算。这就是使用补码的最大的好处。到这里大家有没有发现,int型的这种存储方案是没有考虑小数的,所以这是整型的。关于int型的存储,不再赘述,整体来说还是清晰明了的一种方案。
2、float对32个坑是如何使用的?
同样也是占用32个坑,float型的范围比int就大很多,而且还能表示小数,那么它到底是如何利用这32个坑的呢?
例3:请写出165.25(10进制)使用float型存储在计算机中的形式。
同样我们还是先转换为2进制:
那么如何把上面的二进制小数存到32个坑里呢?
在填坑之前,我们先要规范二进制小数的表示形式,就和我们的科学计数法一样的道理。
(就像
IEEE754标准做了这样的规定:当尾数(小数)不为0时,尾数域的最高有效位为1,这称为浮点数的规格化。
例如:
规格化后的二进制小数,有了统一的规格,可以发现这样规格化之后,我们只需要存储一个尾数(即小数部分,整数部分恒为1)和指数部分。
IEEE754标准把float型的32个坑做了如下划分:
![12a34af4d4fb152005606c05cac6e0d2.png](https://i-blog.csdnimg.cn/blog_migrate/56218f27b0a74582d2517af382c4170b.png)
其中包含了1位符号位S,8位阶码E和23位尾数M。
首先符号位S,0表示正数,1表示负数。S=0;
再写出尾数M,即:M=0100 1010 1000 0000 0000 000;
然后算出阶码E,这里指数为:e=7=0000 0111,根据标准要求,E=e+127;
即:E=7+127=134=1000 0110;
那么把这三个数都填进坑里,就ok啦。
![b7f04ff044bcd55fb2374391e5e01c21.png](https://i-blog.csdnimg.cn/blog_migrate/ddfb11247a7502274e5e01cc9d45a029.png)
这个计算过程稍微复杂点,但也还可以手算出来。
![5bc9ce703d99e8105acf19381939b53e.png](https://i-blog.csdnimg.cn/blog_migrate/d67a8b1c29e47d0280ae987be0888260.png)
但是问题又来了:
1、浮点数的表示范围有多大?
2、为什么要用指数加上127,才是阶码E,而不是直接用指数存进去?
3、这个过程可以看出float有效位是尾数M加1也就是24位,阶码E只是我们规范科学计数法记录指数的,但int有效位是32位,float实际有效位比int少,那么在相互转换的过程中会出现什么问题?
我依次解释这3个问题:
1、浮点数的表示范围有多大?
![3c37eee9fdf8de2d60908aa93e78037a.png](https://i-blog.csdnimg.cn/blog_migrate/f90680525227897f0911b635ab819c68.png)
![500decd7076bd2f2a82567664a29ad92.png](https://i-blog.csdnimg.cn/blog_migrate/c7e1293d5bfaf250ecda3dea2eee6ce3.png)
可以得出当E= 1111 1111时,指数为255-127=128,但这并不是表示这个数是:
那么除了无穷大这个特殊的、人为定义的情况,float型能表示的最大的正整数是多少?最小的负整数是多少?当E= 1111 1111时,是IEEE754定义的特殊值即为无穷大,那么除此之外的最大值就是:E= 1111 1110,M也取最大值,即得到如下结果:
![9a64003a024c30e150df483ee50c1d1b.png](https://i-blog.csdnimg.cn/blog_migrate/c28912be99aef77c08425d5b3fa94fd0.png)
此时阶码E为254,指数即为e=254-127=127。这个数即为:
对于尾数我们可以换一个写法:
1.1111 1111 1111 1111 1111 111=10-0.0000 0000 0000 0000 0000 001
这样尾数可以写成:
那么float能够表示的最大正整数就是:
那么float能够表示的最大负整数就是:
2、为什么要用指数加上127,才是阶码E,而不是直接用指数存进去?
这就很容易说明了,我们举个例子:
例4:请写出0.75(10进制)使用float型存储在计算机中的形式。
写成二进制:
发现问题了没有?这次的指数是个负数啦,而我们希望存储到机器里的阶码永远都是正值,因为我们不希望再浪费一个坑去保存阶码的正负号,于是乎,干脆把指数加上127,而指数能取到的最小值就是-127,这样就可以保证阶码E永远都是正数啦,我们就不用再考虑指数正负号的问题了。
E=-1+127=126=0111 1110;
M=1000 0000 0000 0000 0000 000;
![a5453e4c44bea9c9d4691ed09a904355.png](https://i-blog.csdnimg.cn/blog_migrate/a470eb6c577c3d1f124913d1d13ba320.png)
3、这个过程可以看出float有效位是尾数M加1也就是24位,阶码E只是我们用于规范科学计数法记录指数的,但int有效位是32位,float实际有效位比int少,那么在相互转换的过程中会出现什么问题?
通过问题1知道,float型的表示范围是比int大很多的,但有效位确实只有24位。既然float范围大,那么所有的int型都是可以转换为float型的,这是不会产生溢出报错的。但因为int型有效位是32位,是比float型的24位大的,是有可能发生舍入的,即当一个int型数字,转成float型后,可能就不再是原本数字了,损失了一定的精度。
例如2进制int型正数:0111 1111 1111 1111 1111 1111 1111 1111;
写成科学计数法即为:
小数点后面有30个1,但是我们知道float种尾数M只有23个坑。
则转化为float型后,阶码E=30+127=157=1001 1101
![4902385eb4a9332f39e5b80a442e8eaa.png](https://i-blog.csdnimg.cn/blog_migrate/c906adcd72c2fdbdff8fe663f27b8fe2.png)
可以发现,我们对原int型中存储的数字只保留了小数点后23个1,而后面7个,直接忽视了,这就是发生了舍入。
![dd737b9f9ea0665bea8baac14ead2460.png](https://i-blog.csdnimg.cn/blog_migrate/41347db744b4e920511afffb55cf990d.png)
如果既要范围大,还要保留精度,那就上双精度浮点型double,double型的存储规则和float型是十分类似的。double型有64个坑位,包括了1个符号位S,11个阶码位E和52个尾数位M。所以double的有效位有53位,可以完整保留int。
ok,同样是占32个坑,那凭啥你float就比int的范围更大?因为float型虽然范围大,但是精度不足啊!所以各有千秋哦。
![7957ed5673743dbfcb404a9ba15d272c.png](https://i-blog.csdnimg.cn/blog_migrate/c7bef3e98141f1af38dae0a3286dcd86.png)