C语言中的浮点数存储:深入探讨

案例引入

请看下面一段代码并思考结果:

#define _CRT_SECURE_NO_WARNINGS
#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;
} 

结果如下:

由此可知,C语言中浮点数的存储方式和整数的存储方式是不同的,下面就让我们详细了解一下。 

引言

在C语言中,浮点数用于表示实数,尤其是那些带有小数点的数值。浮点数的存储机制复杂,但它是计算机科学中的重要组成部分。本文将详细介绍C语言中的浮点数在内存中的存储方式,基于IEEE 754标准,并涵盖单精度和双精度浮点数的内部表示。

1. 浮点数的基本概念

浮点数的表示由三个主要部分组成:

  • 符号位(Sign Bit):表示数值的正负。0表示正数,1表示负数。
  • 指数位(Exponent):确定浮点数的范围或数量级。通过调整指数,浮点数可以表示非常大或非常小的值。
  • 尾数(Mantissa):也称为有效数字,表示浮点数的精确值。尾数在计算中决定了浮点数的精度。

2. IEEE 754标准

IEEE 754标准是浮点数存储的国际标准,定义了浮点数的表示和运算规则。

根据国际标准IEEE(电⽓和电⼦⼯程协会) 754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:

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

(−1)^S 表⽰符号位,当S=0,V为正数;当S=1,V为负数
M 表⽰有效数字,M是⼤于等于1,⼩于2的
2^E 表⽰指数位
浮点数的存储,实际上存储的就是S、M、E相关的值。

根据IEEE 754标准,浮点数分为单精度(32位)和双精度(64位)两种格式。

2.1 单精度浮点数(32位)

单精度浮点数使用32位存储,其中包括:

  • 符号位:1位
  • 指数位:8位
  • 尾数:23位(实际尾数有24位,因为有一个隐含的1位)

单精度浮点数的存储格式如下:

对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M。

存储示例:

假设我们要存储浮点数 -5.75。首先将 -5.75 转换为二进制格式,并按照IEEE 754标准进行编码。

表示步骤:
符号位:-5.75 是负数,所以符号位是 1。
绝对值转换为二进制:5.75 的二进制表示是 101.11。
标准化:将 101.11 转换为标准化形式 1.0111 × 2^2。
阶码:IEEE 754 使用偏移量为 127 的阶码。在这里,实际阶码是 2,所以存储的阶码是 2 + 127 = 129,其二进制形式是 10000001。
尾数:标准化形式的尾数部分是 0111,补充至 23 位得到 01110000000000000000000。

因此,-5.75的32位表示为:

1 10000001 01110000000000000000000

2.2 双精度浮点数(64位)

双精度浮点数使用64位存储,其中包括:

  • 符号位:1位
  • 指数位:11位
  • 尾数:52位(实际尾数有53位,因为有一个隐含的1位)

双精度浮点数的存储格式如下:

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

存储示例: 对于浮点数 -5.75,转换步骤如下:

表示步骤:
符号位:-5.75 是负数,所以符号位是 1。
绝对值转换为二进制:5.75 的二进制表示是 101.11。
标准化:将 101.11 转换为标准化形式 1.0111 × 2^2。
阶码:IEEE 754 使用偏移量为 1023 的阶码。在这里,实际阶码是 2,所以存储的阶码是 2 + 1023 = 1025,其二进制形式是 10000000001。
尾数:标准化形式的尾数部分是 0111,补充至 52 位得到 0111000000000000000000000000000000000000000000000000。
最终,64 位双精度浮点数的表示为:

因此,-5.75的64位表示为:

1 10000000001 0111000000000000000000000000000000000000000000000000

3. 内存中的浮点数存储

浮点数在内存中的实际存储取决于系统的字节序(大端或小端)。例如,在大端系统中,较低位字节存储在较高内存地址。以下是如何查看浮点数在内存中的实际存储示例:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
// 将浮点数以大端格式打印
void print_memory_representation(void* p, size_t size) {unsigned char* byte = (unsigned char*)p;// 大端打印需要从高位字节开始for (size_t i = size; i > 0; i--) {printf("%02X ", byte[i - 1]);}printf("\n");
}
int main() {float f = -5.75;double d = -5.75;printf("Float value: %f\n", f);printf("Double value: %lf\n", d);printf("Float类型内存表示(大端):\n");print_memory_representation(&f, sizeof(f));printf("Double类型内存表示(大端):\n");print_memory_representation(&d, sizeof(d));return 0;
}

在此代码中,print_memory_representation 函数将浮点数在内存中的每个字节打印为十六进制格式。运行代码可以观察到浮点数在内存中的具体存储方式。

4. 精度问题与误差

浮点数表示有限精度的实数,可能导致精度问题。例如,0.1 不能精确地用二进制表示,这会在浮点运算中引入微小的误差。因此,比较浮点数时,通常要考虑误差范围,使用一个接近的值进行比较而非直接等于比较。

题⽬解析

下⾯,让我们分析一开始的案例。

先看第1环节,为什么 9 还原成浮点数,就成了 0.000000 ? 9以整型的形式存储在内存中,得到如下⼆进制序列: 

 1 0000 0000 0000 0000 0000 0000 0000 1001


⾸先,将 9 的⼆进制序列按照浮点数的形式拆分,得到第⼀位符号位s=0,后⾯8位的指数
E=00000000 , 最后23位的有效数字M=000 0000 0000 0000 0000 1001。 由于指数E全为0,所以符合E为全0的情况。因此,浮点数V就写成:

V=(-1)^0 × 0.00000000000000000001001×2^(-126)=1.001×2^(-146)
显然,V是⼀个很⼩的接近于0的正数,所以⽤⼗进制⼩数表⽰就是0.000000

再看第2环节,浮点数9.0,为什么整数打印是 1091567616
⾸先,浮点数9.0 等于⼆进制的1001.0,即换算成科学计数法是:1.001×2^3
所以: 9.0 =(-1)^0*(1.001)*2^3那么,第⼀位的符号位S=0,有效数字M等于001后⾯再加20个0,凑满23位,指数E等于3+127=130, 即10000010
所以,写成⼆进制形式,应该是S+E+M,即 1 0 10000010 001 0000 0000 0000 0000 0000
这个32位的⼆进制数,被当做整数来解析的时候,就是整数在内存中的补码,原码正是
1091567616

总结

C语言中的浮点数存储是一个复杂而重要的主题。它涉及到符号位、指数位和尾数的详细布局,以及IEEE 754标准的规范。通过理解浮点数的存储机制,你可以更好地处理浮点数的计算和调试问题。希望本文对你理解C语言中的浮点数存储有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3281324.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Java线程阻塞:原因

Java线程阻塞&#xff1a;原因 1. sleep()2. suspend() 和 resume()&#xff08;不推荐&#xff09;3. yield()4. wait() 和 notify()/notifyAll() &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 线程阻塞是一个重要的概念&#xff0c;它决…

Linux下docker部署drools并集成项目使用

Linux下docker部署drools并集成项目使用 一、背景介绍二、 思路方案三、过程四、总结 一、背景介绍 上一篇文章是对规则引擎的基本介绍&#xff0c;本篇文章是对于drools规则引擎的基本使用。 二、 思路方案 前提&#xff1a;首先保证主机联网、有docker环境、保证Linux空闲…

OS—文件系统

目录 一. 文件系统结构I/O 控制层基本文件系统文件组织模块逻辑文件系统 二. 文件系统布局文件系统在磁盘中的结构主引导记录(MasterBoot Record,MBR)引导块(boot block)超级块(super block)文件系统中空闲块的信息 文件系统在内存中的结构 三. 外存空间管理空闲表法空闲链表法…

面向对象 - 概述、类的创建、 实例化与内存解析

一、学习面向对象的三条主线 Java类及类的成员&#xff1a;&#xff08;重点&#xff09;属性、方法、构造器&#xff1b;&#xff08;熟悉&#xff09;代码块、内部类面向对象的特征&#xff1a;封装、继承、多态、&#xff08;抽象&#xff09;其他关键字的使用&#xff1a;…

北欧风情在浦东,5 大公司为你定制美好

在繁华的浦东&#xff0c;追求高品质生活的您&#xff0c;是否渴望拥有一个充满北欧风情的温馨家园&#xff1f;今天&#xff0c;我们将为您推荐 5 家顶尖的装修公司&#xff0c;它们将以精湛的工艺和独特的设计理念&#xff0c;为您量身定制梦想中的北欧风家居。 推荐一&#…

大数据-56 Kafka SpringBoot与Kafka 基础简单配置和使用

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

大厂的堡垒机到底是啥?为什么需要它?

什么是堡垒机 堡垒机&#xff0c;即在一个特定的网络环境下&#xff0c;为了保障网络和数据不受来自外部和内部用户的入侵和破坏&#xff0c;而运用各种技术手段监控和记录运维人员对网络内的服务器、网络设备、安全设备、数据库等设备的操作行为&#xff0c;以便集中报警、及…

【文件解析漏洞】实战详解!

漏洞描述&#xff1a; 文件解析漏洞是由于中间件错误的将任意格式的文件解析成网页可执行文件&#xff0c;配合文件上传漏洞进行GetShell的漏洞! IIS解析漏洞&#xff1a; IIS6.X&#xff1a; 方式一:目录解析 在网站下建立文件夹的名字为.asp/.asa 的文件夹&#xff0c;其目…

免费发送邮件两种接口方式:SMTP和邮件API

SMTP与邮件API在处理大批量邮件发送时&#xff0c;哪个更稳定&#xff1f; 在现代信息化的社会中&#xff0c;邮件已成为不可或缺的沟通工具。无论是个人还是企业&#xff0c;发送邮件都是日常工作的一部分。AokSend将详细介绍两种常用的免费发送邮件接口方式&#xff1a;SMTP…

麒麟V10系统统一认证子系统国际化

在适配麒麟V10系统统一认证子系统国际化过程中&#xff0c; 遇到了很多的问题&#xff0c;关键是麒麟官方的文档对这部分也是粗略带过&#xff0c;遇到的问题有: &#xff08;1&#xff09;xgettext无法提取C源文件中目标待翻译的字符串。 &#xff08;2&#xff09;使用msgf…

程序一调用这个接口就会崩溃, 因为他的静态库添加是放在release文件下,而我用的debug模式

程序一调用这个接口就会崩溃 因为他的静态库添加是放在release文件下 而我用的debug模式 DESTDIR ../x64/ReleaseINCLUDEPATH ./../3rdparty/ZZDecode/include LIBS -lopengl32 \-lglu32 \-luser32 \./../3rdparty/ZZDecode/x64/release/ZZDecodeInterface.lib

Python软件开发:AI毕业设计生成器引领未来

&#x1f31f; 革新软件开发&#xff1a;Python毕业设计生成器引领未来 &#x1f680; 目录 &#x1f31f; 革新软件开发&#xff1a;Python毕业设计生成器引领未来 &#x1f680;&#x1f393; 课题简介&#x1f31f; 开发目的&#x1f4c8; 开发意义 &#x1f4da; 研究方法&…

Jvm的无关性

Jvm具有无关性&#xff0c;主要体现在两个方面&#xff1a; 平台无关性&#xff1a;任何操作系统都能运行Java代码。 语言无关性&#xff1a;Jvm能运行除Java以外的其他代码。 Java源代码首先需要使用Javac编译器编译成 .class文件&#xff0c;然后由Jvm执行.class文件&…

如何准备 Java API 文档以供下游对接

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119@qq.com] 📱个人微信:15279484656 🌐个人导航网站:www.forff.top 💡座右铭:总有人要赢。为什么不能是我呢? 专栏导…

如何在 Odoo 16 Studio 中添加智能选项卡和管道

具有优雅定制功能的软件系统&#xff08;如 Odoo ERP&#xff09;可让客户调整和个性化其公司应用程序。定制在过去并不普遍&#xff0c;但现在对于组织来说&#xff0c;满足客户需求和需求激增至关重要。即使许多行业的竞争很少&#xff0c;但当前的竞争市场仍不稳定。尽管引入…

Mybatis批量更新数据库错误

问题&#xff1a;记录一次使用Mybatis批量更新数据库的错误&#xff0c;错误信息&#xff0c;Error updating database. Cause: org.postgresql.util.PSQLException: 错误: 字段 "update_time" 的类型为 timestamp without time zone, 但表达式的类型为 text 建议&am…

Prometheus+Grafana 监控平台实践-搭建常用服务监控告警

前言 Prometheus 是一个开放性的监控解决方案,通过各种 Exporter 采集当前主机/服务的数据,和 Grafana 相结合可以实现强大的监控和可视化功能 本篇将分享使用 docker compose 构建 Prometheus+Grafana,并监控之前文章所搭建的主机&服务,分享日常使用的一些使用经验 文…

7月速览| 卓翼飞思获荣誉、助大赛、展技术!

行业殊荣 ● 荣获 “全国低空经济先导产业行业产教融合共同体” 常务理事单位称号&#xff0c;助力打造低空经济产业领域人才智库。 “共同体”是低空经济领域&#xff0c;国家职教战略与新质生产力发展战略融合对接的重要成果。旨在汇聚优质资源&#xff0c;搭建交流平台&…

传统放牧方式与北斗科技的碰撞:北三短报文头羊定位追踪器PD28守护放牧生活

在大草原的广袤天地中&#xff0c;放牧生活是蒙古族人民的传统之一。然而&#xff0c;除了美丽和自由&#xff0c;放牧生活也伴随着一些危险。以前由于科技落后&#xff0c;人工成本低&#xff0c;主要依靠人力去放牧&#xff0c;牧民放牧顶风踏雪走个几十公里都极为寻常。除了…

AI赋能交通治理:非机动车监测识别技术在城市街道安全管理中的应用

引言 城市交通的顺畅与安全是城市管理的重要组成部分。非机动车如自行车、电动车、摩托车等在城市交通中扮演着重要角色&#xff0c;但同时也带来了管理上的挑战。尤其是在机动车道上误入非机动车的现象&#xff0c;不仅影响交通秩序&#xff0c;还可能引发交通事故。思通数科…