C语言——带你深度剖析数据在内存中的存储(下)

简介: C语言——带你深度剖析数据在内存中的存储(下)

次我们讲到了整数在内存中的存储,那么是否大家有没有跟我有同样的疑问————浮点数在内存中的存储是否跟整数是一样的存储方式呢??


话不多说,我们直接看下面代码

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一样呢

我们往下看:

  • 我们思考一下,当我们以整数的形式放进去,以整数的形式拿出来就得到了我们的第一个答案9,但当我们以整数的形式放进去,以浮点数的形式拿出来的时候却不是我们想要的答案,这是不是说明在内存中以浮点数的形式取出来和以整数的形式取出来是不一样的,内存中整数的存储和浮点数的存储是有差异的。
  • 我们也要理解这个答案是如何产生的,这就要我们去搞懂浮点数在计算机内部的表示方法。
  • 根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数V可以表示为:
  • (-1)^S*M*2^E
  • (-1)^S表示符号位     当s=0, V为整数, 当s=1,V为负数
  • M表示有效数字,大于等于1,小于2
  • 2^E表示质数位
  • 我们举个例子:十进制的5.0,写成二进制是101.0 ,相当于1.01x2^2。那么,按照上面V的格式,可以得出s=0,M=1.01,E=2。
  • 十进制的-5.0,二进制是-101.0,相当于-1.01x2^2。那么,s=1,E=2,M=1.01


IEEE 754对有效数字M和E,有特别规定的。当1<=M<=2时,M可以表示为1.xxxxxxxx的形式,其中xxxxxxxx表示小数部分。

IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存xxxxxxxx的部分。比如在保存1.01的时候,只保存了01,等到读取的时候,再把1加上去。


目的:是为了节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去后,等于可以保存24位的有效数字了


对了E,首先E是一个无符号整数,这意味着,如果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,即10001001。


  • E从内存中取出还可以再分成三种情况:
  • 第一种情况:E不全为0和1
  • 这时,浮点数就采用了下面的规则,即E减去127得到真实值,再将有效数字M前面的1加上去。比如:0.5(1/2)的二进制形式为0.1,由于规定整数部分必须为1,即将小数点后移1位,则为1.0*2(-1),按照规则-1要加上127得到126,表示为01111110,而尾数1,0去掉整数部分0,补齐0到23位00000000 00000000 0000000
  • 所以最终的二进制就表示为: 0 01111110 00000000 00000000 0000000
  • 第二种情况:E全为1
  • 这时,如果有效数字M全为0,表示+-无穷大(正负取决于S)。
  • 第三种情况:E全为0
  • 这时,浮点数的指数E等于1-127(或1023),得到真实值,有效数字M不再是加上1,而是还原成0.xxxxxxx的小数形式。这样做是为了表示正负0,以及接近0的数字。
  • 当然我们也要知道为什么不再加上1,真实值应该为-127,浮点数就可以表示为(-1)^S*2^(-127)*1.xxxxxxxx,这个数接近于0的,这时我们就有了这个规定,有效数字M前也不再加上1了

了解玩IEEE 754的规则后,回到我们最开始的问题,为什么0x00000009,还原成浮点数变成了0.000000了呢???       首先将0x00000009拆分,得到第一位符号s=0,后面8位的指数E=00000000 ,最后23位的有效数字为000 0000 00000000 00001001

int main()
{
  int n = 9;
  //9->     0 0000000 0000 0000 0000 0000 0000 1001
  //由于E为全0,所以符合第三种情况。
  //因此浮点数可以表示为V= (-1)^0*0.00000000000000000001001*2*(-126)=1.001*2^(-146)
  //很明显V是一个接近于0的数,所以结果表示为0.000000
  float* pFloat = (float*)&n;
  printf("n的值为:%d\n", n);
  printf("*pFloat的值为:%f\n", *pFloat);
  *pFloat = 9.0;
  //9.0->   1001.0    可以表示为(-1)^0*1.0010*2^3  所以S=0,M=1.0010  E=3
  //我们还原成二进制就是 0 10000010 001 0000  0000 0000 0000 0000
  //这个二级制换成十进制就是  1091567616
  printf("num的值为:%d\n", n);
  printf("*pFloat的值为:%f\n", *pFloat);
  return 0;
}

最后我们用计算机验证一下:


最后:希望这篇文章让你对浮点数的存储有新的认识,我也会不定时更新,分享我的学习经历。

相关文章
|
20天前
|
存储 程序员 编译器
C 语言中的数据类型转换:连接不同数据世界的桥梁
C语言中的数据类型转换是程序设计中不可或缺的一部分,它如同连接不同数据世界的桥梁,使得不同类型的变量之间能够互相传递和转换,确保了程序的灵活性与兼容性。通过强制类型转换或自动类型转换,C语言允许开发者在保证数据完整性的前提下,实现复杂的数据处理逻辑。
|
20天前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
32 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
20天前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
49 6
|
21天前
|
存储 数据管理 C语言
C 语言中的文件操作:数据持久化的关键桥梁
C语言中的文件操作是实现数据持久化的重要手段,通过 fopen、fclose、fread、fwrite 等函数,可以实现对文件的创建、读写和关闭,构建程序与外部数据存储之间的桥梁。
|
23天前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
40 6
|
24天前
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
24天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
22天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
52 1
|
7月前
|
存储 C语言
C语言中的数据输入输出
C语言中的数据输入输出
97 0
|
缓存 C语言
C语言——数据的输入输出
C语言——数据的输入输出