浮点数在内存中的存储方式
前言
参考:浮点数在内存中的存储
引用的链接均采用 CC BY-NC-SA 4.0
许可协议
如果对文章内容有不同意见,欢迎大家到留言板交流讨论。
正文
存储准则
根据国际标准IEEE754(电气和电子工程协会)(下文将简称IEEE754,任意一个二进制浮点数V可以表示成下面的形式:
1 | (-1)^S * M * 2^E |
注:
1、这里的有效数字范围是[1,2),可类比十进制中有效数字的范围是[1,10)。
2、指数部分以2为底数,类比十进制中指数部分以10为底数。
根据IEEE754
标准规定:
对于32位的浮点数(float型),最高的一位是符号位S,接下里8位是指数E,剩下的23位为有效数字M。
对于64位的浮点数(double型),最高的一位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
浮点数的存储与读取方式
浮点数的存储
S :正数S就是0,负数S则是1。
M:M一定是1到2(左闭右开) ,M中小数点前面必然是1,因此1存储在内存中无意义 (如果把1存储进内存反而多占了一位,会降低所保存数字的精度) 。其实只需要在内存中保存小数点后面的几位数字即可。
E:IEEE规定为E开辟的空间只可以存储无符号整数( unsigned int ),但是实际上E却可能是负数,比如0.5。因此IEEE规定E的真实值必须加上一个中间值 (float型E中间值为127,double型为1023),在读取这个浮点数时需要重新减去中间值。
浮点数的读取
1.E不全为0且不全为1
S:直接拿出。
M:从内存中拿出后在前面加上1和小数点
E:减去中间值。
2.E全为0
M:M前面不加1而是加0。
E :E = 1-127 = -126(或者1-1023=-1022)
这样实际上是为了表示无穷小
。
3.E全为1
S:直接拿出。
M:从内存中拿出后在前面加上1和小数点
E :减去中间值。
由于E加上后127为全1,也就是说E的真实值为128,即该浮点数指数部分是128,显然这是一个极大的数,此时表示±∞
(正负号由S决定)
举例
1 | float 5.5 |
关于内存涉及到大小端存储,将在下文详解
内存的大小端存储
首先,让我们先回答,什么是大小端?
对于一个由2个字节组成的16位整数,在内存中存储这两个字节有两种方法:一种是将低序字节存储在起始地址,这称为小端(little-endian)字节序;另一种方法是将高序字节存储在起始地址,这称为大端(big-endian)字节序。
简单来说,大端是高字节存放到内存的低地址,小端是高字节存放到内存的高地址
现在的绝大多数基于X86和ARM的IDE都是小端存储
那么如何确定内存的大小端呢?
我给出一段C语言编写的代码,供大家学习参考
1 | int check_sys()//检测大小端 |
以float型为例,我们都知道1的补码是
1 | 0000 0000 0000 0000 0000 0000 0000 0001 |
也就是十六进制的
1 | 0x00000001 |
而我们又知道,char*这个指针类型决定了指针解引用操作符(*)只能访问一个字节。通过上述对大小端的描述,我们应该不难理解程序的实现原理。
因此,当大家看见
1 | 00 00 b0 40 |
也应该不会感到奇怪了。