float数据类型在内存中的存储方式

浮点数类型float在内存中的存储方式

我们都很熟悉int类型在内存中的存储方式,即直接按照二进制方式存储。我们可以通过以下C语言代码读取到内存中实际是如何储存这些数字的。

int main()
{
	int d = 12345;
	char* p = &d;
	printf("%d : %x, %x, %x, %x\n", d, *(p + 3), *(p + 2), *(p + 1), *p);
	return 0;
}

首先解释为什么是从*(p+3)从大到小逐个输出:
这是因为我们生活中用的电脑都是以小端模式来存储数据的,即数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。
这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

以12345为例,此段代码输出为 0, 0, 30, 39
我们也可以明显观察到,因为12345对于int可保存的数的范围很小,所以只有低位有数字,而高地址*(p+3)、*(p+2)则全部为0。

那么现在来分析一下结果:0, 0, 30, 39
翻译成二进制即为0000 0000 0000 0000 0011 0000 0011 1001
所以2^13 + 2^12 + 2^5 + 2^4 + 2^3 + 2^0 = 12345

如果另有float类型变量f = (float)12345,无疑f会得到12345.000000的值。而如果令f = *(float *)&d,即把d所在的00, 00, 30, 39当做float来看待,得到的f为0

其实这并不是因为格式字符串的问题,而是这个数如果作为float来看待的话,实在是太小了,我们不妨把d设置为1234567890,那么f会得到1228890.250000这个值。
不过,不管怎么看,这两对数字都没有任何关系,这就涉及到float类型的编码问题了:

一个浮点数在内存当中占用4字节,由底数部分m与指数部分e组成。
第1位为符号位,标记该浮点数的正负,1为负数,0为正数。
第2-9位为指数部分e,与该浮点数拥有多少位整数部分相关。
第10-32位为底数部分m,以二进制格式保存实际数据。
所以,浮点数是这样构成的:
SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM

此处,我们用实例来证明:

int main()
{
	float f = 63.75;
	char* p = &f;
	printf("%f : %x, %x, %x, %x\n", f, *(p + 3), *(p + 2), *(p + 1), *p);
	return 0;
}

此代码输出结果为42, 7f, 0, 0
二进制为0100 0010 0111 1111 0000 0000 0000 0000

其中,第一位0代表符号为正。

后面的10000100代表指数位。由于8位二进制可以表示0-255的数字,但是指数应该是可正可负的,所以规定此二进制数减去127才是真正的指数,float可表示指数的范围为-127~128。
而10000100作为二进制数,其值为2^7 + 2^2 = 132,指数应该为132-127 = 5

剩下的就是底数部分。因为底数部分的第一位总是1,所以略去不存储。所以对于底数1111111000…00,其实应该是1.1111111000…00 * 2^5

我们知道对二进制数每左移一位相当于乘以二,为了方便理解,我们把此二进制数左移五位即可得到实际要表示的数,即111111.11000…00
也就是2^5 + 2^4 + 2^3 + 2^2 + 2^1 + 2^0 + 2^(-1) + 2^(-2) = 63.75,和前面一致。

我们可以再求一个数的浮点数储存格式来验证,此处以53.25为例。
首先,53.25为正数,符号位应该为0

53.25的二进制为110101.01,右移5位,得1.1010101。略去首位的1和小数点,也就是底数为1010101000…00,而指数为5+127=132,二进制为10000100

实际存储应该是0100 0010 0101 0101 0000 0000 00000 0000
转化为16进制数为42, 55, 0, 0

验证:

int main()
{
	float f = 53.25;
	char* p = &f;
	printf("%f : %x, %x, %x, %x\n", f, *(p + 3), *(p + 2), *(p + 1), *p);
	return 0;
}

以上代码运行结果 42, 55, 0, 0 验证完毕。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值