C++关于计算浮点数小数位数时遇到的浮点数精确度问题(以及浮点数强制转换问题)

news/2024/11/18 18:43:35/文章来源:https://www.cnblogs.com/xiwen-ydys/p/18292470

起因是当我想要计算浮点数的小数位位数(利用当浮点数num减去其整数位 )
我的想法是先分离出小数位,然后每次循环给小数位乘上10,直到不存在小数位时,就会满足当num - (int)num == 0通过这种方式就可以得到小数位的长度

#include <iostream>
using namespace std;
int main(){double num = 12.34;num = num -(int)num;int len = 0;while(num - (int)num != 0){//当该数减去该数整数位为0时停止循环cout << num << ' ' << (int)num << ' ' << (double)(num - (int)num) << endl;num *= 10;len++;}cout << len << endl;
}

结果出现如下情况且无限循环

该浮点数和该数的整数位相减始终无法得到0,在后续将浮点数进行强制类型转换时发现结果会比预期值少1
经过查阅发现:这是因为浮点数精度丢失导致的(下面我将尽可能详细解释该现象)

第一方面:计算机中数据的存储

首先我们需要知道,在计算机中,所有数据都是以二进制的形式存储的:
如我们所知,在10进制中存在不能精确表示的一些数(无限循环小数)如0.333333...
同理,用二进制数也无法精确表示某些十进制数(其实通常的十进制数都不能用二进制精确表示)
1.234用二进制表示为整数位是1,小数位是00111011111001110110110......
这也造成了浮点数在计算机能是无法精确表示的
但是也有部分可以精确表示的浮点数,如小数点后为0.5, 0.25, 0.125....,如下:

先是浮点数强制类型转换会少一的问题,这个很好解决,如这样(int)(num + 0.5),加0.5即可解决,但是仍然无法解决相减始终无法为0的问题,如下图:

即是看起来整数位对上了,但是结果有多出了很多莫名其妙的很小的小数,这也说明浮点数在计算机中是无法精确表示的。下面我将解释这些很小的小数为何物。

第二方面:C++浮点数存储格式

C++的浮点数是采用IEEE浮点格式进行存储的
什么是IEEE浮点格式呢?
其实就是对浮点数在内存中进行存储的规范。这里就不详细说明(因为我也不太懂),如果有想了解的可以查阅以下链接:
为何浮点数可能丢失精度
Microsoft-IEEE 浮点表示形式
如果希望深一步了解,特别是关于舍入与计算误差方面,推荐阅读著作:
《Sun Studio 11:数值计算指南》
而利用进制转换计算器,我们可以得到这些小数的IEEE标准表示,转换器链接在此:进制转换器

无论是4个字节的float类型还是8个字节的double类型,在其IEEE标准下的十进制表示中,都不是单纯的12.34,而是在其后方有很多很多无法看出规则的小数位,之前浮点数减去整数位所得很小的小数也属于该部分。

总结

出现无法精确相减的原因便是:浮点数存在丢失精度的情况,无论如何都无法得到一个浮点数精确的小数位位数。
但是我们可以通过人为设置一个精度完成我们想要的功能,如下:

#include <iostream>
using namespace std;
int main(){double num = 12.345;int Accuracy = 100000;//设置精度为十的5次方num -= (int)num; //先只保留小数位num *= Accuracy; //用x存储将小数位乘上设置的精度,因为只有整型才能取余//0.345会变成34500, 接着将零去掉,即可得到小数长度int len = 5;while((int)(num + 0.5) % 10 == 0){num /= 10;len--;}cout << len << endl;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

codeforces 955 div 2 D

题目链接 D. Beauty of the mountains 题目大意解题思路 首先记录所有雪山和没有雪山两种山峰的高度差为 \(tot\) ,然后对于每个可能的子矩,我们可以每次给所有山峰都加一或者减一,因此只要计算出矩阵内两种山峰的个数差的绝对值我们就能得到每次操作该子矩阵对tot的贡献 \(…

全局ID工具类

测试方法学习: 定义一个任务(生成id),执行300次,让不同线程执行这300次,用线程池对象的submit方法。心甘情愿做你现在想做的每一件事。

Dubbo源码学习

学习Dubbo框架与手写模拟相关内容 一、存在的意义 Dubbo:解决分布式系统的复杂性,实现服务治理(使服务之间的调用变的简单)和自动注册与发现,简化服务调用。 二、调用过程Dubbo的使用 接口代表一种服务,对应不同的实现,使服务之间的依赖变的简单。 服务消费者通过ClassP…

软件测试的分类and测试进阶路线

本文来自博客园,作者:子沐呐吖,转载请注明原文链接:https://www.cnblogs.com/SuperLee017/p/18292404

使用资源编排 ROS 轻松部署单点网站——以 WordPress 为例

介绍 WordPress是一款免费开源的网站内容管理系统(CMS),它可以帮助用户简单快捷地创建和管理自己的网站,包括博客、新闻网站、电子商务网站、社交网络等等。WordPress 有丰富的主题和插件库,使得用户可以轻松地为网站定制外观和功能。WordPress 的易用性和可扩展性使其成为…

[Java SE] Java-文件系统-常用文件路径的获取方法

1 获取相对路径 /*** 获取相对路径 【推荐】* 使用Java提供的Path类和Paths类来获取相对路径。* 例如,假设有两个路径a和b,我们可以使用Path类的relativize()方法来获取相对路径,该方法返回一个相对路径的Path对象。*/ @Test public void getRelativePathTest1(){Path pathA…

CH582 CH592 CH573 BLE central主机获取handle值

GATT_DiscCharsByUUID和GATT_ReadUsingCharUUID 差异

[深入理解Java虚拟机]Java内存模型

Java内存模型 概述 多任务处理在现代计算机操作系统中几乎已是一项必备的功能了。在许多场景下,让计算机同时去做几件事情,不仅是因为计算机的运算能力强大了,还有一个很重要的原因是计算机的运算速度与它的存储和通信子系统的速度差距太大,大量的时间都花费在磁盘I/O、网络…

深入理解 DB-GPT

DB-GPT 项目介绍 DB-GPT是一个开源的AI原生数据应用开发框架(AI Native Data App Development framework with AWEL(Agentic Workflow Expression Language) and Agents)。目的是构建大模型领域的基础设施,通过开发多模型管理(SMMF)、Text2SQL效果优化、RAG框架以及优化、Mult…

2024年国内最经典好用的5款项目管理软件工具助你一路长虹

目前市场上的项目管理软件众多,但是它们也都有一些共同的功能及特点。比如任务和进度管理、资源分配、财务监控、风险评估、协作增强以及报告和洞察力等。这些功能不仅提供了强大的工具来确保项目的高效执行和按时交付,而且还为团队成员和管理者提供了实时的数据和信息,帮助…

「代码随想录算法训练营」第六天 | 哈希表 part2

454. 四数相加 II题目链接:https://leetcode.cn/problems/4sum-ii/ 题目难度:中等 文章讲解:https://programmercarl.com/0454.四数相加II.html 视频讲解: https://www.bilibili.com/video/BV1Md4y1Q7Yh 题目状态:没思路思路:创建一个unordered_map<int, int>类型的…