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

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

时间:2024-07-09 17:52:55浏览次数:9  
标签:数时 int 浮点数 C++ num 精确 小数位 IEEE

起因是当我想要计算浮点数的小数位位数(利用当浮点数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;
}

标签:数时,int,浮点数,C++,num,精确,小数位,IEEE
From: https://www.cnblogs.com/xiwen-ydys/p/18292470

相关文章

  • C++ pdf库总结
     mupdf#include"widget.h"#include"ui_widget.h"#include<QMessageBox>#include<QDebug>#include<QImage>#include<QPixmap>#include<QLabel>#include"mupdf/fitz.h"#include"mupdf/pd......
  • C++OCR API减轻人们文字录入的负担
    曾几何时,许多大企业会设立文字录入专员的岗位。相信有不少人第一份实习工作就是录入资料,文档、发票、证件等形形色色的文件堆积如山,日积月累的敲击键盘,一张一张的录入电脑系统。这种工作是枯燥的,可以练就文字录入的速度,但是就现在的科技发展的形势来看,录入的工作还是交给OCR来......
  • C++发票识别接口轻松管理财务、发票识别sdk、增值税发票识别
    “营”“增”两种税是主流的流转税种,是两个独立而不能交叉的税种。也就是说交增值税的话就不交营业税,而交了营业税就不需要交增值税。而且,两者在征收的对象、征税范围、计税的依据、税目、税率以及征收管理等都有所不同,增值税在一些方面与营业税相比具有不少优势。营业税......
  • 【Py/Java/C++三种语言OD独家2024D卷真题】20天拿下华为OD笔试之【前缀和/固定滑窗】2
    有LeetCode算法/华为OD考试扣扣交流群可加948025485可上欧弟OJ系统练习华子OD、大厂真题绿色聊天软件戳od1441了解算法冲刺训练(备注【CSDN】否则不通过)文章目录题目描述与示例题目描述输入描述输出描述示例一输入输出说明示例二输入输出说明解题思路贪心思想......
  • C++入门知识
    1.命名空间1.1命名空间的概念在c/c++中,变量,函数,以及类都是大量存在的,这些变量,函数和类的名字会存在全局作用域中,会导致名字重复的问题。使用命名空间的目的是对标识符的名称进行本地化,以避免名字冲突或者名字污染,namespace关键字出现就是针对这种问题。例子:可以打印出rand......
  • c++实战-多子棋
    自创的游戏,可以控制棋盘大小之类的核心在于控制胜利条件,需要每次扫描代码如下:#include<iostream>#include<vector>usingnamespacestd;#defineMAX_SIZE9//定义棋盘为MAX_SIZExMAX_SIZE的二维向量vector<vector<char>>board(MAX_SIZE,vector<char>(MAX_SIZE......
  • c++临时对象导致的生命周期问题
    对象的生命周期是c++中非常重要的概念,它直接决定了你的程序是否正确以及是否存在安全问题。今天要说的临时变量导致的生命周期问题是非常常见的,很多时候没有一定经验甚至没法识别出来。光是我自己写、review、回答别人的问题就犯了或者看到了许许多多这类问题,所以我想有必要做个......
  • C++-时间复杂度
    前言    OJ测试中最烦人的结果莫过于TLE(TimeLimitExceed 超时)和MLE(MempryLimitExceed超内存)了,在递归和搜索题里面看见这两货就烦。目录前言时间复杂度         时间复杂度概念时间复杂度的表示法        时间复杂度OJ测试要求   ......
  • 基于SpringBoot的酒店订房系统+82159(免费领源码)可做计算机毕业设计JAVA、PHP、爬虫、A
    springboot酒店订房系统摘 要随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,酒店订房系统当然也不能排除在外。酒店订房系统是以实际运用为开发背景,运用软件工程开发方法,采用springboot技术构建的一个管理系统......
  • 分享一些算法开局技巧(C++)
    目录一、万能头文件二、一些宏定义操作三、提前定义好一些常用的值四、快读五、一键获取题目的案例数据六、一键生成代码模板总结:个人心得一、万能头文件一般算法需要用到各种头文件,但是万能头文件包括了绝大多数的头文件,能缩减一些代码量。但是也有一点副作用,由于......