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

news2024/11/13 6:32:47

案例引入

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

#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://www.coloradmin.cn/o/1963041.html

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

相关文章

如何实现参加RAG比赛但进不了复赛的总结

今天写这篇文章主要就是总结一下我使用的一些基本方法&#xff0c;虽然肯定比不上前十的大佬们的操作&#xff0c;但对于常规RAG实现来说也是够用的。这次的考题是给了一堆HTML的知识文档&#xff0c;基于这些文档来进行知识问答。这些文档是企业内部的运维相关文档&#xff0c…

点击jmeter.bat一闪而过无法打开的解决方案

重新查看了配置&#xff0c;在系统变量&#xff08;win10以上直接搜索“环境变量”&#xff09;配置了所有的配置&#xff0c;点击jmater.bat一闪而过无法打开&#xff0c;并且在命令行输入jmeter如下的提示&#xff1a; 检查JMETER_HOME在系统变量的配置是否有分号&#xff0c…

windows 上使用纯 nvcc 命令编译 myboyhood/yolo-tensorrt 工程的过程记录

1. 码云仓库链接&#xff1a;https://gitee.com/myboyhood/yolo-tensorrt 2. 参考博客&#xff1a; 1. 用C/C写一个简单的音乐播放器&#xff08;基于windows控制台编程&#xff09;&#xff1a;https://blog.csdn.net/lwx1051046458/article/details/128889992 3. 过程记录&…

Linux中新添加的磁盘信息不显示-主动扫盘(刷新磁盘状态)

在Linux系统中&#xff0c;当你新添加了一个磁盘&#xff08;无论是通过物理添加还是虚拟化环境&#xff09;&#xff0c;你可能需要让系统识别这个新磁盘&#xff0c;并且可能需要更新或“刷新”磁盘的状态。这通常涉及到几个步骤&#xff0c;但没有一个直接的“刷新磁盘状态”…

springboot集成nacos开启权限验证报错:user not found!

按照官网的说明对nacos的application.properties配置做了开启权限配置。 我的配置项&#xff1a; spring:cloud:nacos:discovery: #服务发现配置group: devnamespace: integrated-manage-dev password: integrated_manageusername: integrated_manageserver-addr: lo…

手把手教你实现基于丹摩智算的YoloV8自定义数据集的训练、测试。

摘要 DAMODEL&#xff08;丹摩智算&#xff09;是专为AI打造的智算云&#xff0c;致力于提供丰富的算力资源与基础设施助力AI应用的开发、训练、部署。 官网链接&#xff1a;https://damodel.com/register?source6B008AA9 平台的优势 &#x1f4a1; 超友好&#xff01; …

Java 延迟消息

场景 6S后执行任务 7天后发送订单 从现有时间算延后多少时间开始执行&#xff0c;当然也可以转换为在以后某个时间执行。 Timer类 Java中的Timer类是一个定时器&#xff0c;它可以用来实现延时消息的功能。 import java.util.Timer; import java.util.TimerTask;public c…

uniapp微信小程序本地和真机调试文件图片上传成功但体验版不成功

文章目录 导文是因为要添加服务器域名&#xff01; 导文 uniapp微信小程序本地和真机调试文件图片上传成功但体验版不成功 uniapp微信小程序体验版上传图片不成功 微信小程序本地和真机调试文件图片上传成功但体验版不成功 是因为要添加服务器域名&#xff01; 先看一下 你小程…

android13 第三方桌面不能使用后台历史任务问题 任务键功能失效问题

总纲 android13 rom 开发总纲说明 目录 1.前言 2.复现现象 3.问题分析 4.解决方法 5.编译运行 6.彩蛋 1.前言 随着Android 13操作系统的发布,用户现在可以更加自由地选择和使用第三方Launcher来定制自己的设备。本文将介绍在Android 13上安装和使用第三方Launcher导致…

工信部哪些证书可以考,含金量高吗

随着科技的快速发展和行业的不断变化&#xff0c;市场对人才的需求也在不断更新。技能提升可以帮助个人适应这些变化&#xff0c;满足新的岗位要求。同时学习新技能可以拓宽思维&#xff0c;激发创新意识&#xff0c;帮助我们在工作中找到新的解决方案。 泰迪智能科技专注…

楼宇智能化仿真实训室解决方案

在信息技术的浪潮中&#xff0c;智慧城市作为未来城市发展的新形态&#xff0c;正以前所未有的速度在全球范围内兴起。其中&#xff0c;楼宇智能化作为智慧城市的关键构成&#xff0c;扮演着举足轻重的角色。它不仅提升了建筑的能源效率、安全性与舒适度&#xff0c;还促进了城…

SQL Server 端口配置

目录 默认端口 更改端口 示例&#xff1a;更改 TCP 端口 示例&#xff1a;验证端口设置 远程连接测试 示例&#xff1a;使用 telnet 测试连接 配置防火墙 示例&#xff1a;Windows 防火墙设置 远程连接测试 示例&#xff1a;使用 telnet 测试连接 默认端口 TCP/IP: …

【Github】Github 上commit后 contribution 绿格子不显示 | Github绿格子 | Github贡献度不显示

一、Github 消失的绿点 1、贡献值为什么没了&#xff1f; 2、选择要显示的贡献 如下配置 二、如何解决消失的绿点&#xff1f; 1、添加邮箱 确保邮箱的设置必须选择一个邮箱邮箱 2、git config 添加邮箱 设置邮箱如下&#xff1a; git config --local user.email 316434776…

Tomcat IntelliJ IDEA整合

一、下载及安装Tomcat 下载官网&#xff1a;Apache Tomcat - Welcome! 1.点击红色框中的任意一个版本 2.点击下载 3.解压后放在任意路径&#xff08;我的是放在D盘&#xff09; 4.在bin目录下找到startup.bat&#xff0c;点击启动Tomcat 5.如果双击启动后&#xff0c;终端出…

NC 缺失的第一个正整数

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 描述 给定一个无重…

无人机之交通管理篇

无人机技术已经渗透到社会的各个领域&#xff0c;其中交通监控与管理便是其应用的重要方向之一。无人机凭借其独特的优势&#xff0c;如高效性、灵活性、实时性等&#xff0c;为交通监控与管理带来了革命性的变革。 一、无人机在交通监控中的应用 1、实时监控与数据采集 无人…

cdga|数据治理策略:击破壁垒,迈向纵向一体化的新纪元

在当今这个数据驱动的时代&#xff0c;企业数据的价值日益凸显&#xff0c;它不仅是企业决策的重要依据&#xff0c;更是推动业务创新、优化运营流程、增强市场竞争力的关键要素。然而&#xff0c;随着数据量的爆炸性增长和数据来源的多样化&#xff0c;企业面临着数据孤岛、数…

时常在面试中被问到的JVM问题

文章目录 JVM 和 JDK、JRE 有什么区别&#xff1f;JVM 是如何工作的&#xff1f;JVM 主要组件JVM 执行流程JVM 的工作示例 说一下类加载机制类加载器&#xff08;Class Loader&#xff09;示例 什么是双亲委派模型&#xff1f;&#xff08;Parent Delegation Model&#xff09;…

时间同步的原理

1.问题来源&#xff1a; 设备A想要给设备B同步时间&#xff0c;最直接的办法&#xff0c;A发送当前时间到B&#xff0c;但这个问题会带来一些问题。 1.1 例子&#xff1a; 设备A&#xff08;后面叫Master设备&#xff09;现在拥有准确时间9点整, 设备B&#xff08;后面叫Sla…