[c语言日寄]浮点数在内存中的储存

devtools/2025/2/8 15:38:51/

在这里插入图片描述

【作者主页】siy2333
【专栏介绍】⌈c语言日寄⌋:这是一个专注于C语言刷题的专栏,精选题目,搭配详细题解、拓展算法。从基础语法到复杂算法,题目涉及的知识点全面覆盖,助力你系统提升。无论你是初学者,还是进阶开发者,这里都能满足你的需求!
【食用方法】1.根据题目自行尝试 2.查看基础思路完善题解 3.学习拓展算法
【Gitee链接】资源保存在我的Gitee仓库:https://gitee.com/siy2333/study


文章目录

  • 前言
  • 1. 题目引入
  • 2. 功能介绍
    • 2.1 浮点数的基本概念
    • 2.2 IEEE 754标准
    • 2.3 浮点数的存储格式
      • 组成成分
      • 内存映射
    • 2.4 浮点数的表示范围
  • 3. 注意事项
    • 3.1 精度问题
    • 3.2 特殊值
    • 3.3 比较浮点数
  • 4. 题目解答
    • 代码分析
  • 总结


前言

在计算机科学中,浮点数是一种用于表示实数的数据类型。与整数不同,浮点数可以表示非常大或非常小的数值,并且能够处理小数部分。然而,浮点数在内存中的存储方式与整数有很大的不同,本文将深入探讨浮点数在内存中的存储方式,帮助读者更好地理解这一概念。


1. 题目引入

我们先看这样一个案例,观察一下程序运行的结果:

#include<stdio.h>int main() {int n = 9;float* p_float = (float*)&n;printf("n的值为:%d\n", n);printf("*n_float的值为:%f\n", *p_float);*p_float = 9.0;printf("n的值为:%d\n", n);printf("*n_float的值为:%f\n", *p_float);return 0;}

请添加图片描述
第一个输出结果比较易懂,但是为什么另外三个的值会是这样的呢?

2. 功能介绍

2.1 浮点数的基本概念

浮点数是一种用于表示实数的数据类型。它由两部分组成:尾数M(mantissa)和指数E(exponent)。尾数表示数值的有效数字,而指数表示数值的缩放比例。通过这种方式,浮点数可以表示非常大或非常小的数值。

2.2 IEEE 754标准

IEEE 754是浮点数表示的国际标准,定义了浮点数在内存中的存储格式。根据IEEE 754标准,浮点数可以分为单精度(32位)和双精度(64位)两种类型。单精度浮点数使用32位存储,其中1位用于符号,8位用于指数,23位用于尾数。双精度浮点数使用64位存储,其中1位用于符号,11位用于指数,52位用于尾数。

2.3 浮点数的存储格式

组成成分

在IEEE 754标准中,浮点数的存储格式如下:

  • 符号位(Sign Bit):1位,表示浮点数的正负。0表示正数,1表示负数。
  • 指数位(Exponent):8位(单精度)或11位(双精度),表示浮点数的指数部分。指数部分采用偏移量表示法,即实际指数值为存储值减去一个固定的偏移量。
  • 尾数位(Mantissa):23位(单精度)或52位(双精度),表示浮点数的尾数部分。

举个例子,9.5(单精度)在内存中的内容要通过以下方式计算:

  1. 将整数和小数部分转化为二进制数:1001.1(注意,小数点后的1代表2^0.1,即0.5);
  2. 移动小数点使其变成1.xxxxx的形式:原式 = 1.0011 x 2^3
  3. 此时,尾数部分就是小数点后面的部分,即M = 0011
  4. 指数部分为2^后面的部分,也就是3,加上常数127,得到值130,转换为而二进制:E = 10000010
  5. 由于9.5为正数,所以符号位为0,即S = 0
  6. 我们将其按照S-E-M的顺序补位,得到:0-1000 0010-0000 0000 0000 0000 0000 011
  7. 也就是说,9.5在内存中的储存内容就是01000001000000000000000000000011

内存映射

单精度和双精度的内存映射如下:在这里插入图片描述

2.4 浮点数的表示范围

由于浮点数的存储方式,其表示范围受到指数和尾数的限制。

  • 单精度浮点数的表示范围约为±3.4×10^38^;
  • 双精度浮点数的表示范围约为±1.8×10^308^

然而,浮点数的精度受到尾数位数的限制,单精度浮点数的精度约为7位十进制数,双精度浮点数的精度约为15位十进制数。

3. 注意事项

3.1 精度问题

浮点数的精度受到尾数位数的限制,因此在处理非常大或非常小的数值时,可能会出现精度损失。例如,两个非常接近的浮点数相减可能会导致结果不准确。为了避免这种情况,可以使用更高精度的浮点数类型(如双精度浮点数)或采用数值稳定的算法。

我们看下面的代码:

#include<stdio.h>int main() {float a = 3.14;printf("%f", a);return 0;
}

我们在调试中查看a在内存中的值
在这里插入图片描述
其中04 84 5f 3c转换成二进制为0-10010000-1000 1011 1110 0111 100
不难发现,3.14的小数部分无法被精确表示,因为每一个位数,都是2的n次方:2-1、2-2 、2-3……

3.2 特殊值

IEEE 754标准定义了一些特殊值,如正无穷大(+∞)、负无穷大(-∞)和非数字(NaN)。这些特殊值用于表示某些特殊情况,如除以零或无效运算。

3.3 比较浮点数

由于浮点数的精度问题,直接比较两个浮点数是否相等可能会导致错误的结果。通常,可以使用一个很小的阈值(如ε)来判断两个浮点数是否近似相等。例如,判断|a - b| < ε是否成立,而不是直接判断a == b。

4. 题目解答

代码分析

  1. 变量声明与初始化

    int n = 9;
    float* p_float = (float*)&n;
    
    • int n = 9; 声明了一个整数变量 n 并将其初始化为 9
    • float* p_float = (float*)&n; 声明了一个指向浮点数的指针 p_float,并将其初始化为指向 n 的地址。这里使用了类型转换 (float*),将 n 的地址(原本是 int* 类型)强制转换为 float* 类型。
  2. 第一次输出

    printf("n的值为:%d\n", n);
    printf("*n_float的值为:%f\n", *p_float);
    
    • printf("n的值为:%d\n", n); 输出 n 的值,此时 n 的值是 9,所以输出为 n的值为:9
    • printf("*n_float的值为:%f\n", *p_float); 输出 p_float 所指向的值。由于 p_float 是一个 float* 类型的指针,而 n 是一个 int 类型的变量,*p_float 会将 n 的内存内容解释为一个浮点数。
  • n此时在内存中的值为:00000000-00000000-00000000-00001001
  • 按照浮点类型解释:0-00000000-00000000000000000001001,是一个非常小的数。
  1. 修改指针指向的值

    *p_float = 9.0;
    
    • *p_float = 9.0;p_float 所指向的内存位置的值修改为 9.0。由于 p_float 指向的是 n 的内存地址,因此 n 的内存内容被修改为浮点数 9.0 的二进制表示。
  2. 第二次输出

    printf("n的值为:%d\n", n);
    printf("*n_float的值为:%f\n", *p_float);
    
    • printf("n的值为:%d\n", n); 输出 n 的值。由于 n 的内存内容被修改为浮点数 9.0 的二进制表示,因此 n 的值现在是一个与 9.0 的二进制表示相对应的整数。同理,这个值是一个非常大的整数。
    • printf("*n_float的值为:%f\n", *p_float); 输出 p_float 所指向的值。由于 p_float 指向的内存内容已经被修改为 9.0,因此输出为 *n_float的值为:9.000000

总结

浮点数在内存中的存储是一个复杂的过程。本文详细介绍了浮点数的基本概念、IEEE 754标准、存储格式、表示范围、精度问题等。希望通过本文的介绍,读者能够更好地理解这一知识点。

关注窝,每三天至少更新一篇优质c语言题目详解~

[专栏链接QwQ] :⌈c语言日寄⌋CSDN
[关注博主ava]:siy2333
感谢观看~ 我们下次再见!!


http://www.ppmy.cn/devtools/157116.html

相关文章

《手札·开源篇》基于开源Odoo软件与Deepseek的智能企业管理系统集成方案

一、方案背景 随着企业数字化转型的深入&#xff0c;传统ERP系统需要结合AI技术实现智能化升级。本方案将开源ERP系统Odoo与深度求索&#xff08;Deepseek&#xff09;大模型能力深度整合&#xff0c;构建具备智能决策支持、自然语言交互和数据分析增强的企业管理平台。 二、…

STM32的HAL库开发---通用定时器(TIMER)---定时器脉冲计数

一、脉冲计数实验原理 1、 外部时钟模式1&#xff1a;核心为蓝色部分的时基单元&#xff0c;时基单元的时钟源可以来自四种&#xff0c;分别是内部时钟PCLK、外部时钟模式1&#xff0c;外部时钟模式2、内部定时器触发&#xff08;级联&#xff09;。而脉冲计数就是使用外部时钟…

基于Bootstrap + Java + Oracle实现的电商平台

以下是基于Bootstrap Java Oracle实现的电商平台开发方案&#xff08;简化版&#xff09;&#xff1a; 一、系统架构设计 前端&#xff1a;Bootstrap 5 jQuery 后端&#xff1a;Java Spring Boot 数据库&#xff1a;Oracle 19c 自动化&#xff1a;Spring Scheduler Oracle…

在rtthread中,scons构建时,它是怎么知道是从rtconfig.h找宏定义,而不是从其他头文件找?

在rtthread源码中&#xff0c;每一个bsp芯片板级目录下都有一个 SConstruct scons构建脚本的入口&#xff0c; 在这里把rtthread tools/目录下的所有模块都添加到了系统路径中&#xff1a; 在tools下所有模块中&#xff0c;最重要的是building.py模块&#xff0c;在此脚本里面…

cs106x-day1

开始打卡cs106x(Autumn 2017)-lecture1 cs106x这门课的介绍&#xff1a; 主要通过 C 语言让学生在实际的编程作业里培养通过编程抽象解决实际问题的能力&#xff0c;同时也会涉及一些简单的数据结构和算法的知识&#xff0c;但总体来说没有一门专门的数据结构课那么系统。 1、…

数据分析:企业数字化转型的金钥匙

引言&#xff1a;数字化浪潮下的数据金矿 在数字化浪潮席卷全球的背景下&#xff0c;有研究表明&#xff0c;只有不到30%的企业能够充分利用手中掌握的数据&#xff0c;这是否让人深思&#xff1f;数据已然成为企业最为宝贵的资产之一。然而&#xff0c;企业是否真正准备好从数…

硬件实现I2C案例(寄存器实现)

一、需求分析 二、硬件电路设计 本次案例需求与前面软件模拟案例一致&#xff0c;这里不再赘述&#xff0c;不清楚可参见下面文章&#xff1a;软件模拟I2C案例&#xff08;寄存器实现&#xff09;-CSDN博客 值得注意的是&#xff0c;前面是软件模拟I2C&#xff0c;所以并没有…

东方财富股吧发帖与评论爬虫

东方财富股吧发帖与评论爬虫 东方财富股吧爬虫 写在开头项目介绍主要功能文件介绍爬取逻辑 a. 爬取帖子信息b. 爬取评论信息 使用步骤 1. 下载代码2. MongoDB 安装3. Webdriver 安装4. 运行 main.py5. 查看数据 踩过的坑附录&#xff08;运行结果&#xff09; 东方财富股吧爬…