里面详细介绍了整型跟浮点型的存储,看完认可的话,可否一键三连呢!
数据类型介绍
我们大致分为2类:整型与浮点型
整型:int,char,short,long,long long
浮点型:float(单精度浮点型),double(双精度浮点型)
补充一点,我之前一直在犯错的地方:
float类型的输入(scanf)用“%f”,打印用“%lf”或者“%f”
double类型的输入(scanf)用“%lf”,打印用“%lf”或者“%f”
问:为什么要这么多数据类型?
为了开辟不同的内存空间大小,可以精确控制存在这些空间中的数据
整型在内存中的存储
一个数据它有原码、补码、反码,我们通常操作的是它的补码,存在内存中的也是它的补码
接下来介绍一下怎么实现3者之间的转换:(正数的反码补码是本身,不会改变,负数则要遵循以下原则,且符号位不变(最左边的第一位))
我们举个例子:(a是整型,占4个字节=8个比特位,因此存到a中的只有8个有效数字)
下面我们看负数的:(为了效率,我们就只写前和后的8个比特位)
我们可以验证(每4个二进制位等于1个16进制位)例如:
注意:每4位二进制位转化为一位16进制位
问:为什么要用整型补码进行计算 ?
答:用补码可以将符号位和数值统一处理,避免了正负数符号不同产生影响
我们看个例子:
下面我们仔细演示一遍:
大小端的介绍
其实就是大端存储和小端存储
如果高字节位存储到低地址位,就是大端存储(逆序),否则就是小端存储(顺序)
我们画个图理解:
如何判断当前编译器版本是小端存储还是大端存储?
我们可以写一个代码,看它的内存存储
我们可以看到,在内存中a的存储是f6 ff ff ff
刚好与我们换算的16进制相反,所以我们判断是大端存储
因此,我们可以这么记:顺序为小端,逆序为大端
浮点型内部的计算方法
浮点数的存储与我们的整型存储截然不同,它需要先转化再存储,首先我们先看一个公式:
V=(-1)^S * M * 2^E
我们演示以下,帮助理解:
解析:我们拿左边为例
首先5.5是一个浮点数,先转化小数点左边为2进制,再把右边也换成2进制(小数点右边第一位是乘2的负一次方,小数点右边第二位是乘2的负二次方,以此类推),然后再移动小数点进行变换
下面我们重点讲变化规律:
V= (-1)^S * M * 2^E
“(-1)^S”是符号位,S=0时,V为正数;S=1时,V为负数;
“M”是有效数字,范围是1<=M<=2,(在上面的移动小数点就是要移动到M满足这个条件为止)
“2^E” 是指数位,2代表2进制,E代表移动位数(左移是正号,右移是负号)
了解完之后,我们再正式进入浮点数的存储
浮点数存储详细剖析
IEEE 754规定:
对于32位浮点数(float类型),它的最高位是符号1,接着8位是指数E,剩下的23位是有效数字E(画的有点不好看啊.........)
我们再看64位浮点数(double类型),它的最高位是符号位1,接着11位是指数E,剩下的52位是数字E
存储:
1:S位如果是有符号就是存储 0,无符号就是存储1
2:存M的时候:只存小数点后面的数字,比如1.678,就只存678三个数字,取出的时候再加上1(注意加在个位啊)
3:因为E(无符号整数),可能出现E为负数的情况,所以E的真实值必须加上一个中间数,如果是float类型就加上127,比如(-1+127);如果是double类型就加上1023,比如(-1+1023);拿出来的时候再减去对应加的值就行了
取出:(主要是针对E,因为M的取出会根据E变化)
取出E我们分3类
E不全为0或者不全为1:E等于减去127/1023,再给M加上1
E全为0:E等于1-127或者1-1023即为真实值,M不加1
E全为1:如果有效数字M全为0,表示无穷大
我们举个例子:
我们在内存中验证一下(因为是大端存储方式,所以逆序)
下面我们进行演示怎么将它取出来:(再根据之前的转换回去,就是5.5了)
为了更好的理解我们再举个例子
我们分解解释:
1:第一个就是打印整型n,我们就直接跳过
2:
3:
4:
就是一个赋值成浮点数,打印的也是浮点数,因此还是9.000000