【C语言】浮点数在内存的储存

前言:

在上章,了解了整数在内存中的储存,在本章节为大家继续讲解浮点数的储存,也是数据储存的最后一部分。

浮点数是计算机科学中一种重要的数据类型,用于表示实数。它能够表示非常大或非常小的数值,并且可以处理小数部分。然而,浮点数的存储方式与整数完全不同,其存储原理和特性也决定了浮点数在使用过程中存在特殊。

介绍:

浮点数的概念:

浮点数是一种用来表示实数的数据类型,其特点是小数点的位置可以浮动。

浮点数由三个部分组成:符号位(Sign)、指数位(Exponent)和尾数位(Mantissa)。符号位表示数值的正负,指数位表示数值的大小范围,尾数位则表示数值的具体精度。

浮点数的存储格式通常遵循IEEE 754标准,这是目前计算机系统中最常用的浮点数存储规范。IEEE 754标准定义了单精度浮点数(32位)和双精度浮点数(64位)两种主要格式。

常见的浮点数:3.1415926,1E10等,浮点数包含的类型有float,double,long double 浮点数的表示范围在头文件float.h中定义。

单/双精度

  • 单精度浮点数(32位)

    单精度浮点数由1位符号位、8位指数位和23位尾数位组成。具体存储方式如下:

    • 符号位:1位,0表示正数,1表示负数。
    • 指数位:8位,采用偏移量为127的二进制补码形式存储。
    • 尾数位:23位,实际存储时省略了最高位的隐含1(即实际存储23位,但计算时加上隐含的1),这样可以节省存储空间。
  • 双精度浮点数(64位)

    双精度浮点数由1位符号位、11位指数位和52位尾数位组成:

    • 符号位:1位,0表示正数,1表示负数。
    • 指数位:11位,采用偏移量为1023的二进制补码形式存储。
    • 尾数位:52位,同样省略了最高位的隐含1。

浮点数的范围与精度

  • 范围

    根据IEEE 754标准,单精度浮点数可以表示的数值范围为:

    2^-126∼2^127

    双精度浮点数的范围更广,可以表示更大的数值。

储存的原理

根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:

V = (-1)^S * M * 2^E

(-1)^S表示符号位,当S=0,V为正数;

当S=1,V为负数。

M表示有效数字,大于等于1,小于2。

2^E表示指数位。
举例:

十进制的5.0,写成二进制是 101.0 ,相当于 1.01×2^2 因为是二进制所以 底数是2 ,小数点向左移动了俩位所以指数是2 那么,按照上面V的格式,可以得出 S=0,M=1.01,E=2。

十进制的-5.0,写成二进制是 -101.0 ,相当于 -1.01×2^2 ,那么,S=1,M=1.01,E=2

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

如图所示:

对于64位的浮点数,最高的1位是符号位S, 接着的11位是指数E,剩下的52位为有效数字M。

有效数字M和指数E的特别规定

IEEE 754对有效数字M和指数E,还有一些特别规定

  • 前面说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。
  • IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。
  • 比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。
  • 以32位浮点数为例,留给M只有23位, 将第一位的1舍去以后,等于可以保存24位有效数字。

至于指数E,情况就比较复杂。

首先,E为一个无符号整数(unsigned int)

  • 这意味着,如果E为8位,它的取值范围为0 ~ 255;
  • 如果E为11位,它的取 值范围为0 ~ 2047。但是,我们知道,科学计数法中的E是可以出现负数的。
  • 所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是 127
  • 对于11位的E,这个中间数是 1023

比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即 10001001。

取出原理

指数E的三种情况
(1) E不全为0或不全为1

这时,浮点数就采用下面的规则表示:

  • 即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。

比如:

  • 0.5(1/2)的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,则为
  • 1.0*2^(-1),其阶码为 -1+127=126,表示为 01111110,
  • 而尾数1.0去掉整数部分为0,补齐0到23位 00000000000000000000000。 所以 S=0 E=126 M=0 参考前面浮点数的储存模型可知 则其二进制表示形式为:

0 01111110 00000000000000000000000

(2)E全为0

这时,浮点数的指数E等于1-127(或者1-1023)即为真实值。

有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及无限接近于0的很小的数字。

(3)E全为1

这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)

例题

大家可以计算一下输出结果

cs 复制代码
#include <stdio.h>
int main()
{
	int n = 9;
	float* pFloat = (float*)&n;
	printf("n的值为:%d\n", n);
	printf("*pFloat的值为:%f\n", *pFloat);
	*pFloat = 9.0;
	printf("num的值为:%d\n", n);
	printf("*pFloat的值为:%f\n", *pFloat);
	return 0;
}

欧克,结果如下:

我猜部分帅哥,美女的结果都是:9  9.000000  9  9.000000

这是为什么呢?接下来只要好好思考一下浮点数的存储方式大家就明白了。

第一个简单:

n是 int类型,所以我们输出是以整形格式取出然后以%d十进制方式打印。

printf("*pFloat的值为:%f\n", *pFloat); 这个的话上难度了。

这个是对float类型的指针解引用但他指向地址是个整形 而整形类型的在计算机存储的是补码:

9转成二进制就是 00000000000000000000000000001001

而按浮点数类型拿出的话 S=0 E=0 M= 0...1010

这里就是指数E为0的时候 套用浮点数计算公式 V = (-1)^S * M * 2^E

我们拿出的是一个无限接近0的一个小数 而%f只打印6个零就不打印了所以我们打印的是: 0.000000
*pFloat = 9.0; printf("num的值为:%d\n", n);

这个打印为什么是1091567616

这段代码第一句话向指针指向的地址存进去了一个浮点数9.0

而浮点数的存储9.0 二进制是1001 写成科学计数法是 1.001

所以S=0 M=1.001 E=130 所以在内存存的是: 0 10000010 00100000000000000000000 转成十进制打印就是1091567616
*pFloat = 9.0;

*pFloat的值为:%f\n",

*pFloat这个是以浮点数的形式打印,而我们存进去的就是浮点数所以 打印还是9.0

总结:

本章讲解了浮点数的概念;

存取原理 ;

希望对大家有所帮助。

有所帮助的话,关注一手把,我们下章再见!!!!

相关推荐
Bt年3 分钟前
浮点数精度问题(CSP38思考)
开发语言·c++·算法
天天进步20157 分钟前
Java应用性能监控与调优:从JProfiler到Prometheus的工具链构建
java·开发语言·prometheus
dragon09071 小时前
Python打卡day49!!!
开发语言·python
摩天崖FuJunWANG1 小时前
c语言中的hashmap
java·c语言·哈希算法
LUCIAZZZ1 小时前
Java设计模式基础问答
java·开发语言·jvm·spring boot·spring·设计模式
IsPrisoner1 小时前
Go 语言实现高性能 EventBus 事件总线系统(含网络通信、微服务、并发异步实战)
开发语言·微服务·golang
秋水丶秋水1 小时前
电脑桌面太单调,用Python写一个桌面小宠物应用。
开发语言·python·宠物
大得3691 小时前
go全局配置redis,全局只需要连接一次,然后全局可以引用使用
开发语言·redis·golang
字节高级特工1 小时前
【Linux篇】细品环境变量与地址空间
linux·运维·服务器·c语言·c++·ubuntu·centos