从原理浮点数的四舍五入问题

简介: 本文探讨了浮点数在计算机中的存储与运算误差问题。通过分析 `printf("%.1f", 3.155)` 的输出结果为 3.15 而非预期的 3.16,揭示了浮点数存储时因二进制转换和位数限制导致的精度损失。进一步解释了 IEEE 754 标准下浮点数的存储结构,包括符号位、指数位和尾数位,并以 0.05 为例详细说明其二进制科学计数法表示及存储形式。最后,通过在计算中加入小偏移量(如 +0.0005)解决了保留小数位时的四舍五入问题,成功实现预期输出。此分析有助于理解浮点数运算误差及其应对方法。

​
在某一天的刷题中,偶然写道了这道题

image.png

写完以后发现没有满分,由此引发了猜想,对于编译器运行时使用

printf("%.1f",3.155);
其它本身就会进行四舍五入所以会出现以下运行结果
image.png

但如果我们保留两位小数呢?

image.png

啊,不该是输出3.16么?为什么是3.15呢?

我们带着疑问对a进行监视
image.png

原来如此,a在存储时不是存的3.155,而是3.15499997,那么自然保留两位小数就是3.15了嘛;

为什么会有误差呢?

原因如下

浮点数在计算机中存储时,小数部分也是按二进制存储的;例如:0.9 十进制转换为二进制是:0.111001100110011001100…无限循环而计算机中存储的位数是有限的,因此当变量存储不了后面的二进制小数时,再转换回十进制就产生误差了float: 单精度浮点数 十进制保存7位置,二进制保存23位0.111001100110011001100…转换回十进制就是:0.89999998。double: 双精度浮点浮点数由于存储空间不够引起的截断误差
回归本题(链接:学生基本信息输入输出
牛客题霸_牛客网 (nowcoder.com))

浮点数储存原理:
针对于与float类型的浮点数,我们知道其大小为四个字节

然而对于数学的科学计数法来说如果对于有个小数,比如0.05;针对于科学计数法来说,我们一般不按照他为0.05来说,而是按照(-1)^0*5.0x10^(-2);来说,那么计算机总不能直接来按照0.05来存储吧,毕竟我根据上面的验证,也大致得知了,存储的时候可能无法精准的进行存储,而是存储一个非常接近的数字,无限接近的数,所以计算机就是按照科学计数法的方法进行存储浮点数的

而0.05,同样对于0.06,我们通过科学计数法表示就为(-1)^0*6.0x10^(-2);所以对于0.05,我们只需要存储该数的重要部分便可以,也就是 0 5.0 -2。至于后续怎么保存,我们就需要查找了。

但是又回过来了,我们都知道计算机存储的时候不是以十进制存储,而是以二进制方法存储到文件,以二进制读取,后转化为十六进制进行显示,

那么大致原理便知道了

那么对于这四个数,每一部分都是位于不同位置,所以存储的时候也尤其对应的位置

比如,国际标准IEEE(电气和电子工程协会)754中就有相关规定
image.png

所以0.05的存储方法便知道了

首先

但是根据前面监测查看实际内存存储情况来看,其实并不会将一个小数精准保存,而是保存一个非常接近的数,所以那0.05为例,他的二进制表示在计算机看来并不会使用0.0000110011001100110011001100110011001100110011001101...(无限循环)来表示的而是进行小数位后面一些不必要的取舍,对于取舍多少位是由用户存的为float还是double。

对于此

image.png

所以0.05如果为float那么他的二进制用科学计数法表示为:1.10011001100110011001101 × 2^(-5)。

所以IEEE 754 单精度浮点数表示:

image.png

s=0 M=1.10011001100110011001101 E=-5

那么话又回过来了,0.05实际上的S位与M位就是存的为

0 ???????? 10011001100110011001101

E为一个负数,但在IEEE754规定E为一个无符号的整数,那么到底怎么存的呢?

IEEE754规定:

image.png

所以E其实存的是-5+127=122;123二进制表示为01111010

所以二进制存储为:

0 01111010 10011001100110011001101

温馨提示
并不是所有的浮点数都不能精确的进行存储,只是有的部分浮点数不能比如3.14都可以,但是0.1都不可以,如果想要验证的话可以自己尝试一下,可以通过在vs的调试很简单的验证。
存储原理就是以上,说完了以后那么我们就知道为什么要+0.005,为什么有时候又不需要加了 。
那么保留两位小数,我们直接在加0.005就可以了嘛

include

int main()
{
unsigned long long int p;
double a, b, c;
scanf("%llu;%lf,%lf,%lf", &p, &a, &b, &c);
if(a!=0)
a = a + 0.0005;
if(b!=0)
b = b + 0.0005;
if(c!=0)
c = c + 0.0005;
printf("The each subject score of No. %llu is %.2lf, %.2lf, %.2lf.", p, a, b, c);
return 0;
}

image.png

成功!!!
​

目录
相关文章
|
存储 编解码 算法
LDPC 在 5G-NR 中的标准进展之基本图 | 带你读《5G-NR信道编码》之十三
本章节将带读者走进5G LDPC 码基本图矩阵,带你了解LDPC有哪些基本图的设计。
10686 110
LDPC 在 5G-NR 中的标准进展之基本图 | 带你读《5G-NR信道编码》之十三
|
数据格式
STM32外设系列—红外遥控
本文详细介绍了红外通信的应用,原理。介绍了一种常用的二进制脉冲码形式。最后,给出了红外遥控的实现思路和程序设计。
2209 2
STM32外设系列—红外遥控
|
9月前
|
存储 弹性计算 人工智能
2026年最新阿里云无影云电脑收费价格:企业版、个人版及免费版配置收费清单
阿里云无影云电脑2026年升级配置与计费体系,覆盖企业版、个人版及免费试用。企业版分四类,支持灵活时长包与高性能图形工作站;个人版推五档核时套餐,适配办公与游戏;新用户可享免费试用。按需选择,降本增效。
|
开发者 Docker 微服务
《深入探秘:从底层搭建Python微服务之FastAPI与Docker部署》
FastAPI是一款基于Python 3.6+的现代、高性能Web框架,结合Starlette和Pydantic优势,支持异步编程,性能媲美Go与Node.js。它内置输入验证、依赖注入功能,自动生成交互式API文档,大幅提升开发效率与代码质量。Docker容器技术通过封装应用及其依赖,实现“一次构建,到处运行”,解决环境差异问题,提供轻量级、高效的部署方案。两者结合助力快速搭建稳定、高效的Python微服务架构,满足高并发与弹性伸缩需求,推动现代化应用开发。
605 9
《深入探秘:从底层搭建Python微服务之FastAPI与Docker部署》
空口资源 | 带你读《5G 空口设计与实践进阶 》之十四
NR对空口物理资源的划分包括 3 个维度,即时域、频域和空域。为了满足各种差异化应用场景的要求,NR 在对“时—频—空”物理资源的管理上,除继承 LTE 的基础外,也进行了大量的革新,包括自适应的波形、更为灵活的帧结构、可配置的参数集、部分带宽等。
空口资源 | 带你读《5G 空口设计与实践进阶 》之十四
|
编译器 C语言
C语言宏定义(#define定义常量​、#define定义宏​、 带有副作用的宏参数、 宏替换的规则、 宏函数的对比)
C语言宏定义(#define定义常量​、#define定义宏​、 带有副作用的宏参数、 宏替换的规则、 宏函数的对比)
|
机器学习/深度学习 并行计算 测试技术
每天五分钟深度学习:解决for循环效率慢的关键在于向量化
通过本文的介绍,希望读者能够理解向量化的基本概念、优势及其在实际应用中的重要性,并能够在日常的深度学习工作中灵活应用向量化技术,从而提升工作效率和代码性能。
776 13
|
Windows
DOS 批处理 setlocal命令、endlocal命令详解
setlocal这是一个命令,它开始局部化环境更改,通常在批处理文件中使用,以确保在脚本中所做的任何环境更改(例如设置或修改环境变量)不会影响到调用此批处理的上下文或其他批处理文件
1121 14
|
开发工具 git
git clone避坑的万能步骤
git clone避坑的万能步骤
3388 1
|
安全 文件存储 iOS开发
告别痕迹:远程桌面连接历史和凭据的清零指南
【8月更文挑战第18天】使用远程桌面后,为保障安全隐私,需清除连接历史及凭据。在Windows中,可通过注册表编辑器删除HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default下的MRU键值来清除历史记录;macOS下则需移步至“~/Library/Application Support/Apple/Remote Desktop”删除“Clients.plist”。清除凭据方面,Windows用户应访问“控制面板”中的“凭据管理器”删除相应条目;macOS用户需利用“钥匙串访问”应用找出并移除相关条目。
6177 3