您的位置:首页 > 理论基础

浮点数在计算机中存储方式

2016-05-15 16:06 288 查看
首先,咱们先得知道,在计算机内存中存储数据的格式有两种,一种是大端字节序(即将高位数据存放在低地址上,低位数据存放在高地址上),还有一种是小端字节序(与之前相反),举个例子:

一个short int短整型 3332 == 00001101 00000100,那么大部分机器中的存储方式为小端字节序

那就是这么存的: 00000100 00001101,也就是低位数据(4)放在低地址,高位数据(3328)放在高地址上。

x86,MOS Technology 6502,Z80,VAX,PDP-11等处理器为小端字节序,也就是说我们常用的绝大多数机器都是小端字节序。知道了这一点再来讨论浮点数是如何存储在内存上的这个问题。

c/c++的所有编译器都是采用IEEE指定的标准浮点格式规则,即二进制科学表示法。

在这种表示方法中,一个数S = M*2^N

其中N表示阶码,M表示尾数(有效数字位),这里我们假定一个float型数,4个字节,32bit位

【31】 N:【30~23】 M:【22~0】

31位是符号位:0正,1负

中间8位是阶码位:表示范围为【-128~127】,对于float型数据规定其偏移量为127(下面解释)

后面23为是有效数字位:因为科学计数法,整数位定死了是1,所以这里记录的是小数点后面的二进制位

指数N决定它的范围,因为M总是一个以1开头的小数,以float来说即是:-2 ^ 128 ~~ 2 ^ 128,即float能表示的数的大小范围。

而它的精度是由尾数(也就是有效数据位)来决定的,2 ^ 23 == 8388608 ,总共7位,这表示最多能有7位有效数字,最多能表示到 .8388608 即小数点后7位,由于不能完全表示完全部的7位数,所以它的精度范围为6位~~7位。

同理可得double的精度是2 ^ 52 == 4503599627370496,共16位,所以精度为15~~16位。

具体该是怎么转换存到内存中去的呢?见下

假定一个float型数125.5

1.125的二进制表示形式为01111101,小数部分0.5表示为2^-1,用二进制表示也就是 .1,那么合起来就是01111101.1,这样一来我们使用上面的公式来表示的话就是125.5 == 1.1111011 * 2 ^ 6,N = 6

2.得到阶码为6,加上float型规定偏移量127,为133 == 10000101

3.得完了阶码,求尾数,将整数部分去掉得到 1111011,尾数有23位,不足的地方补0,即是1111011 00000000 00000000

4.这是一个正数,取符号位0

结合以上得到的数据,这个125.5的二进制表示形式为:

0 10000101 1111011 00000000 00000000

31 30 ~ 23 22 ~ 0

它在内存中存放的形式为小端字节序即:

00000000 00000000 11111011 01000010

我们可以这么记大小端字节序,低位数据放在低位地址就是小端,低位数据放在高位地址就是大端。即:低位数据在哪(大小端)一端,就对应大小端。

假设要根据二进制表示形式计算对应的浮点数:

假设浮点数为01000010 11111011 00000000 00000000

1.首位是0,这是一个正数

2.阶码是(1000010 == 133) - 127 == 6 == N

3.尾数为1111011 00000000 00000000,得到0.1111011,加上整数部分恒为1,得到1.1111011 == M

4.S = M * 2 ^ N == 1.1111011 * 2 ^ 6,二进制,小数点向右移动6位,最终得到两部分,1111101.0 == 2 ^ 7 - 2 ^ 1 +2 ^ -1 == 125 + 0.5 == 125.5

还存在一种情况,当float型数没有整数部分时候,如0.5的表示,稍微有点不同

要构建上面的等式S = M * 2 ^ N,而M的整数部分恒为1,所以这个0.5 == 2 ^ -1,也就是0.1,为了保证整数部分为1,这时候不能向左边移动了,向右移动一位,得到1.0 ,N == -1 + 127 == 126 == 01111110,得到了N,1.0去掉整数部分就是0了,给它补齐23位,就是23个0,这是个正数,所以最后的结果是:

0 01111110 0000000 00000000 00000000

double类型的数据也是类似,计算时不同的是阶码要换成11位偏移量是1023尾数52位

在下面的网站中还有更详细的测试,用一个char型指针分别指向一个float变量的4个字节,如125.5按照在内存中存储的格式是00000000 00000000 11111011 01000010,就是 0 0 -5 66 ,第三位char是单字符型,范围-128~127

且二进制在内存中是以补码的形式储存的

前面两位是0,第三位是负数,负数的补码形式是将其绝对值的二进制(就是除去符号位的其他位数)形式按位求反再加1,so对后7位取反再+1,得到5,加上负号,得到-5

第四位是0开头,正数,由于正数的补码和其原码形式相同,直接求后七位得到66

参考资料:

/article/4719940.html

总结:

不同机器上字节序的规定

公式:S = M * 2 ^ N

二进制在内存中是以补码的形式存储,负数要对其二进制绝对值按位取反再加一正数的补码和原码形式相同

float/double类型的范围和精度的计算方式
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: