C语言:浮点数内存存储机制

目录

目录

浮点数详细解读

1.小数的转换

2.浮点数的存储规则

3.浮点数的范围

4.浮点数的精度

 5.内存详解


我们可以很快速的理解整型数在计算机中的存储模式,这是因为整型以二进制形式直接存储于内存中,而对于进制转换,是我们在学习计算机之初就已有所了解。

但是浮点数是一个困扰许多人的问题,因为其在内存中特殊的存储形式,使得不熟悉这种规则的人们无法理解,就比如下面的代码:

#include <stdio.h>

int main()
{
	int x = 0x41440000; 
	float* fp = (float*)&x;
	printf("&x = %08x ,x  = %d \n", &x, x); 
	printf("fp = %08x ,*fp = %f \n", fp, *fp);
	*fp = 10.25;
	printf("&x = %08x ,x  = %d \n", &x, x);
	printf("fp = %08x ,*fp = %f \n", fp, *fp);

	return 0;
}

 输出的代码结果让我们产生困惑,为什么相同地址空间存储的数据,结果会出现那么大差距?

原来问题在于,int 和 float 类型的存储方式,我们所知道的,int 类型占4字节,其中最高一个bit位为符号位,其余31个bit位为数值位。

由图可以见得,整型的内存存储仅是将数值转变以二进制方式存储,但浮点数不同,接下来,我们来详细解读浮点数的内存存储规则

浮点数详细解读

1.小数的转换

小数向二进制转换的规则为:乘2取个位值,值是0,取0,值是1,取1,直到乘为0为止。

我们以12.25为例:取出小数部分,反复对其进行乘2操作,取结果的个位为当前小数位的值,再取结果的小数位重复以上操作,直到剩余的小数部分为0

2.浮点数的存储规则

根据国际标准IEEE754(电气和电子工程协会),任意一个二进制浮点数X可以表示成下面的形式 :
    (-1) ^ S * M * 2 ^ E

  • (-1)^S 表示符号位,当S = 0,X为正数; 当S = 1,X为负数。
  • M表示有效数字,大于等于1,小于2。
  • 2 ^ E 表示指数位。

例:       (12.25)10→(1100.01)2; X的格式是: (-1) ^ 0 * 1.10001 * 2 ^ 3; S = 0,M = 1.10001; E = 3;
              (-0.25)10→(-0.01)2  ;    X的格式是:  (-1) ^ 1 * 1 * 2 ^ -2;           S = 1, M = 1; E = -2;

注意:IEEE754标准做了这样的规定:当尾数(小数)不为0时,尾数域的最高有效位为1,这称为浮点数的规格化。

例如 : (165.25)10→(1010 0101.01)2 -> (1.010010101 * 2^7);
           规格化后的二进制小数,有了统一的规格,可以发现这样规格化之后,我们只需要存储一个尾数(即小数部分,整数部分恒为1)和指数部分。

1.IEEE754规定:对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M。如图:
 

 2.IEEE754规定:对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。如图:

  • M规格化: frac被描述为小数值,且O≤frac<1,其二进制表示为0.frac。尾数定义为M=1+frac,则M=1.frac。那么就有1<M<2,由于总是能够调整阶码E,使得M在范围1≤M<2,所以不需要显示的表示它,这样还能获得一个额外的精度位。也就是说,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的frac部分,等到读取的时候,再把第一位的1加上去。
  • M在规格化时,小数点可能左移,如:1100.01规格化为1.10001小数点左移3位,使1<=M<2;而0.001规格化为1小数点右移3位,使1<=M<2;
  • E是8位二进制数(无符号数),表示范围是О~255;取中间位127;如果小数点左移n位,n为正值;如果小数点有移n位, n为负值;E= n + 127;

3.浮点数的范围

以float为例:

我们由前面的储存规则可以了解,浮点数的阶码E初始时保持中间值127,如果小数点左移n位,n为正值,如果小数点有移n位, n为负值,

E = n + 127,那么float的存储范围最大约为2^{127},最小约为2^{-127}

4.浮点数的精度

float的精度为6-7位,因为尾数M的位数为23,那么其可以存储精度为2^{24} - 1也就是6-7位

float的精度为15-16位,因为尾数M的位数为52,那么其可以存储精度为2^{53} - 1也就是15-16位

 5.内存详解

回归刚开始的代码,为什么出现结果的差异,实际上是编译器对不同类型的解读方式不同

将x的值按照float来解读,可得符号位 0,阶码 10000010 可得 n =  +3, 尾数 1.10001

可推出*fp = 1100.01,即也就是12.25

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值