当前位置: 首页 > news >正文

62.【C语言】浮点数的存储

目录

1.浮点数的类型

2.浮点数表示的范围

3.浮点数的特性

《计算机科学导论》的叙述

4.浮点数在内存中的存储

答案速查

分析

前置知识:浮点数的存储规则

推导单精度浮点数5.5在内存中的存储

验证

浮点数取出的分析

1.一般情况:E不全为0或不全为1

2.特殊情况:E全为0

3.特殊情况:E全为1

回到本题分析

1.printf("n的值为:%d\n", n);

2.printf("*pFloat的值为:%f\n", *pFloat);

3.printf("num的值为:%d\n", n);

4.printf("*pFloat的值为:%f\n", *pFloat);

5.其他注意事项


1.浮点数的类型

float,double,long double等等

2.浮点数表示的范围

在float.h中介绍

以下截取一部分

#define FLT_MAX          3.402823466e+38F        // max value
#define FLT_MAX_10_EXP   38                      // max decimal exponent
#define FLT_MAX_EXP      128                     // max binary exponent
#define FLT_MIN          1.175494351e-38F        // min normalized positive value
#define FLT_MIN_10_EXP   (-37)                   // min decimal exponent
#define FLT_MIN_EXP      (-125)                  // min binary exponent

FLT_MAX是float类型的最大值,FLT_MIN是float类型的最小值

3.浮点数的特性

浮点数在内存中无法精确保存

《计算机科学导论》的叙述

摘抄图

4.浮点数在内存中的存储

求下列代码的执行结果

#include <stdio.h>
int main()
{int n = 9;//&n被强制类型转换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;
}

答案速查

分析

前置知识:浮点数的存储规则

对《计算机科学导论》的浮点数总结后:

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

如十进制+5.5==101.1==1.011*2^2(此时S==0,M==1.011且1<M<2,E==2)

754标准的特殊规定

1.由于M总是可以写成1.??????的形式,因此,在计算机内部保存M时,默认这个数的第一位总是

1,因此可以被舍去,只保存后面的??????部分。比如保存1.01的时候,只保存01,等到读取的时

候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有

23位,将第一位的1舍去以后,等于可以保存24位有效数字

2.指数E

IEEE规定:E为无符号整数(unsigned int)

但在科学计数法中的E是可以出现负数的,因此IEEE修正为:

存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023

例如:在32位中,E为8位:-2-->-2+127-->125-->补码为0111 1101

在x64+debug环境下,将下列代码调试,下断点至return 0;

#include <stdio.h>
int main()
{float f = 5.5;return 0;
}

推导单精度浮点数5.5在内存中的存储

float是单精度(32位),double是双精度(64位)-->这里的32位和64位与电脑的运行环境没有关系!!

十进制5.5按IEEE标准写法:5.5=(-1)^0*1.011*2^2

现按照"S+E+M"的形式存储

S=0,E为2,2+127=129=1000 0001,M=1.011

舍去M的第一位,并补满23位

最终为 0 10000001 011000000000000000000004

转换为十六进制:0100 0000 1011 0000 0000 0000 0000 0000

-->40 B0 00 00

验证

x86+debug环境下,打开内存窗口,输入&f

f在内存中存储为00 00 b0 40(小端序存储)

浮点数取出的分析

1.一般情况:E不全为0或不全为1

按存储规则反过来还原即可

2.特殊情况:E全为0

指数E等于1-127(或1-1023)

注意:这里不是0-127或0-1023!如果E为0,则权为2^0,这样就不能表示小数!则下方所说的极小的小数也就不成立了

有效数字M不再加上第一位的1,而是还原为0.xxxxxx的极小的小数(权为2^{-126})(趋近于+0或-0)

3.特殊情况:E全为1

11111111b=255-->255-127=128(权为2的128次方),表示+∞或-∞(正负取决于符号位S)

回到本题分析

1.printf("n的值为:%d\n", n);

整型数字以整型打印,为9

2.printf("*pFloat的值为:%f\n", *pFloat);

整型9以单精度浮点打印

整型9在内存中的存储为09 00 00 00

-->把小端序换为正常的表示顺序 0000 0000 0000 0000 0000 0000 0000 1001

-->按按照"S+E+M"的形式重新排列

0 0000000 00000000000000001001

S=0,E全为0-->2的-126次方-->(-1)^0*9*2^{-126}

说明浮点数极小-->被忽略-->输出0.000000(默认保留小数前6位)

3.printf("num的值为:%d\n", n);

9.0-->S=0(正数:原码=反码=补码),E=2^{3},M=1.001-->3+127=130=1000 0010b

0 10000010 00100000000000000000000

按整型的形式排列:0100 0001 0001 0000 0000 0000 0000 0000

对应十六进制:41 10 00 00-->小端序存储-->在内存中排布为01 00 00 41

4.printf("*pFloat的值为:%f\n", *pFloat);

单浮点数以单浮点形式打印,为9.0

5.其他注意事项

有写十进制浮点数转换成二进制会有偏差

如3.14

二进制只能表示这样的2^1,2^0,2^{-1},2^{-2},2^{-3},2^{-4},...,2^{-n}

具体转换的方式见《计算机科学导论》

所以在比较浮点数时可能会出现错误

复制以下代码到不同的编译器上测试

#include <stdio.h>
int main()
{if (3.14 == 3.12 + 0.2){printf("==");}else{printf("!=");}
}

 VS2022

VS2019

Dev C++ TDM-GCC 4.9.2

结果都一样且正确

复制以下代码到不同的编译器上测试

#include <stdio.h>
int main()
{float a = 0.3;float b = 0.2;float c = 0.1;if (a == b + c){printf("==");}else{printf("!=");}
}

VS2022

VS2019

Dev C++ TDM-GCC 4.9.2

结果不一样,不同的编译器的精度不一样

浮点数的判断有专门的写法:比差值+规定误差(精度)

#include <stdio.h>
#include <math.h>
int main()
{if (fabs(3.12 + 0.2 - 3.14)<0.2){printf("==");}else{printf("!=");}
}

函数fabs为求浮点数绝对值函数,需要写 #include <math.h>

相关文章:

  • unity_Occlusion_Culling遮挡剔除学习
  • 从两个 Excel 表格中提取相关信息,并根据学生的 学号 和 姓名 将第一个表格中的成绩数据填充到第二个表格中(附Python代码)
  • 什么是 JWT?它是如何工作的?
  • vue数组根据某些条件进行二次切割
  • 1.2.1 HuggingFists安装说明-Linux安装
  • 如何用Prometheus监控禁用了Actuator的SpringBoot?
  • 渗透测试--文件上传常用绕过方式
  • Python编码系列—Python责任链模式:打造灵活的请求处理流程
  • 鸿蒙HarmonyOS之封装Http请求工具类
  • Llama微调以及Ollama部署
  • MRC接收机
  • 【数字图像处理】小白也能懂,最浅显方式手撕直方图均衡化(附python实现)
  • python 02 List
  • 药物临床试验机构备案信息数据库查询方法(支持数据下载)
  • Git常用方法——详解
  • 【5+】跨webview多页面 触发事件(二)
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • Android 架构优化~MVP 架构改造
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • js递归,无限分级树形折叠菜单
  • LeetCode29.两数相除 JavaScript
  • select2 取值 遍历 设置默认值
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • yii2权限控制rbac之rule详细讲解
  • 理清楚Vue的结构
  • 深入浅出Node.js
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • elasticsearch-head插件安装
  • UI设计初学者应该如何入门?
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • $$$$GB2312-80区位编码表$$$$
  • $L^p$ 调和函数恒为零
  • %3cli%3e连接html页面,html+canvas实现屏幕截取
  • (1)(1.13) SiK无线电高级配置(五)
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (arch)linux 转换文件编码格式
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (STM32笔记)九、RCC时钟树与时钟 第二部分
  • (vue)页面文件上传获取:action地址
  • (二) 初入MySQL 【数据库管理】
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (回溯) LeetCode 131. 分割回文串
  • (简单) HDU 2612 Find a way,BFS。
  • (四)模仿学习-完成后台管理页面查询
  • (图文详解)小程序AppID申请以及在Hbuilderx中运行
  • (转)h264中avc和flv数据的解析
  • (转)linux 命令大全
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • ****三次握手和四次挥手
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .Net Core 生成管理员权限的应用程序
  • .net core使用RPC方式进行高效的HTTP服务访问
  • .NET/C# 检测电脑上安装的 .NET Framework 的版本
  • .NET大文件上传知识整理