浮点数的比较以及abs和fabs的区别

『踩坑记录』浮点数的比较以及abs和fabs的区别

  • Chapter1 『踩坑记录』浮点数的比较以及abs和fabs的区别
    • abs函数与fabs函数的区别
      • 相同点:
      • 不同点:
  • Chapter2 浮点数为什么不能用 == 进行比较
    • 浮点数比较方法
    • 判定相等
    • 拓展:


Chapter1 『踩坑记录』浮点数的比较以及abs和fabs的区别

我们知道有的小数可能小数点后有很多为,比如无限循环小数、无限不循环小数,而计算机中的float和double能够表示的小数范围是有限的,因此浮点数在计算机中的存储是不精确的。

浮点数判断相等当在float或double表示精度范围内时可以直接使用==比较,但是更多情况下是比较两个数的差的绝对值小于float或double表示的精度误差就可以认为这两个浮点数相等。
float的精度误差为1e-6,double的精度误差为1e-15。

在C++中,abs和fabs都是用来计算数值的绝对值的函数,但它们之间存在一些重要的区别。

1.函数定义:
abs:这个函数是C++标准库中的一部分,定义在头文件中。它通常用于整数类型的绝对值计算。
fabs:这个函数是C语言标准库中的一部分,定义在头文件中。它通常用于浮点数的绝对值计算。
2.参数类型:
abs:接受一个整数作为参数。
fabs:接受一个浮点数作为参数。
3.返回类型:
abs:返回一个整数。
fabs:返回一个浮点数。
4.精度:
abs:对于整数,精度取决于具体的实现和平台。
fabs:对于浮点数,精度取决于具体的实现和平台,但通常足够用于大多数的数值计算。
5.用途:
abs:通常用于计算整数的绝对值。
fabs:通常用于计算浮点数的绝对值。
在这里插入图片描述
使用abs求浮点数的绝对值是有问题的,使用fabs求整数的绝对值也是有问题的,所以在C语言中求浮点数的时候一定要选对函数。

在这里插入图片描述
abs的用法
abs() 方法在C语言中,只对int整型生效,作用是求整型数据的绝对值。

头文件:

#include<stdlib.h>

abs() 方法在C++语言中,只对double、float、long double类型生效,不支持int类型,作用是求数据的绝对值。从C++11开始,增加了对int整型数据类型的支持。

头文件:

#include<cmath>

abs函数与fabs函数的区别

相同点:

1.都是获取绝对值
2.头文件都需调用#include或者是<math.h>

不同点:

1、abs函数在C语言中只能求出整数的绝对值,在C++中能作用任何类型数据,fabs函数在C++中对任何数据类型都能求绝对值。
对于C语言来说, abs只能用于整型数据,fabs只能用于浮点型数据;
对于C++来说, std::abs和std::fabs都既可以用于整型,又可以用于浮点型。当用于整形时,std::abs返回的是整形,而std::fabs返回的是浮点型。

另外,std::abs的使用范围会更广些,出来刚才提到的基本类型外,std::abs还可以作用于std::complex和std::valarray

// cmah定义了fabs();cstdlib定义了abs(),labs();但这些都是继承自C的。//数学函数,所在函数库为math.h、stdlib.h、string.h、float.h 
int abs(int i) 返回整型参数i的绝对值 
double cabs(struct complex znum) 返回复数znum的绝对值 
double fabs(double x) 返回双精度参数x的绝对值 
long labs(long n) 返回长整型参数n的绝对值 
double exp(double x) 返回指数函数ex的值 
double frexp(double value,int *eptr) 返回value=x*2n中x的值,n存贮在eptr中 
double ldexp(double value,int exp); 返回value*2exp的值 
double log(double x) 返回logex的值 
double log10(double x) 返回log10x的值 
double pow(double x,double y) 返回xy的值 
double pow10(int p) 返回10p的值 
double sqrt(double x) 返回+√x的值 
double acos(double x) 返回x的反余弦cos-1(x),x为弧度 
double asin(double x) 返回x的反正弦sin-1(x),x为弧度 
double atan(double x) 返回x的反正切tan-1(x),x为弧度 
double atan2(double y,double x) 返回y/x的反正切tan-1(x),y的x为弧度 
double cos(double x) 返回x的余弦cos(x),x为弧度 
double sin(double x) 返回x的正弦sin(x),x为弧度 
double tan(double x) 返回x的正切tan(x),x为弧度 
double cosh(double x) 返回x的双曲余弦cosh(x),x为弧度 
double sinh(double x) 返回x的双曲正弦sinh(x),x为弧度 
double tanh(double x) 返回x的双曲正切tanh(x),x为弧度 
double hypot(double x,double y) 返回直角三角形斜边的长度(z), 
x和y为直角边的长度,z2=x2+y2 
double ceil(double x) 返回不小于x的最小整数 
double floor(double x) 返回不大于x的最大整数 
void srand(unsigned seed) 初始化随机数发生器 
int rand() 产生一个随机数并返回这个数 
double poly(double x,int n,double c[])从参数产生一个多项式 
double modf(double value,double *iptr)将双精度数value分解成尾数和阶 
double fmod(double x,double y) 返回x/y的余数 
double frexp(double value,int *eptr) 将双精度数value分成尾数和阶 
double atof(char *nptr) 将字符串nptr转换成浮点数并返回这个浮点数 
double atoi(char *nptr) 将字符串nptr转换成整数并返回这个整数 
double atol(char *nptr) 将字符串nptr转换成长整数并返回这个整数 
char *ecvt(double value,int ndigit,int *decpt,int *sign) 
将浮点数value转换成字符串并返回该字符串 
char *fcvt(double value,int ndigit,int *decpt,int *sign) 
将浮点数value转换成字符串并返回该字符串 
char *gcvt(double value,int ndigit,char *buf) 
将数value转换成字符串并存于buf中,并返回buf的指针 
char *ultoa(unsigned long value,char *string,int radix)

Chapter2 浮点数为什么不能用 == 进行比较

原文链接:https://blog.csdn.net/weixin_53306029/article/details/119352531

《深入理解计算机系统》中这样说过,浮点数普遍的作为实数运算的近似值的计算,是很有用的。这里说的是实数的近似值的计算,所以浮点数在计算机中其实是一种不精确的表示。它存在舍入误差。IEEE浮点标准用符号,尾数和阶码将浮点数的位表示划分为三个字段,单精度为32位,双精度为64位,因为表示方法限制了浮点数的范围和精度,浮点运算只能近似的表示实数运算。而 == 表示的是在计算机中的内存表示完全一样,因此使用 == 来表示两个浮点数的相等就会出现问题。

浮点数比较方法

由于计算机中采用的是有限位的二进制编码,所以浮点数在计算机中的存储不总是精确的,这种情况下会对比较操作带来极大的干扰,所以我们需要引入一个极小数 eps 来对这种误差进行修正,判断一下这两个数的绝对值,即在数轴上的距离是否小于某个精度 eps。

判定相等

如果一个数 a 在 [b-eps, b+eps] 的区间中时,就应当判断为 a==b 成立.
经验表明, eps 取 10-8是一个合适的数字——对大多数的情况既不会漏判,也不会误判。因此,我们可以将 eps 定义为常量 1e-8

const double eps = 1e-8;

为了使比较更加方便,我们可以将比较写成宏定义的形式:

#define Equ(a, b) ((fabs((a) - (b))) < (eps))

使用不等于,只需要在使用时的 Equ 前面加一个非运算符 “ ! ” 即可( ! Equ(a, b))。此时在程序中就可以使用 Equ 函数来对浮点数进行比较了。
下面让我们对之前的例子重新进行比较:

#include<iostream>
using namespace std;
#define eps 1e-8
#define Equ(a, b) ((fabs((a) - (b))) < (eps))
int main()
{double a = (double)1.0;double b = (double)0.0;for (int i = 0; i < 10; ++i)b += 0.1;if (Equ(a, b))cout << "true" << endl;elsecout << "false" << endl;return 0;
}

拓展:

判断一个浮点数是否为0是通过下面的方法来实现的。
浮点数因为存储形式的原因不能直接和0值比较,判断一个浮点数是否等于0时:
fabs(x)<=1e-6 就是认为是0了。

float,double分别遵循R32-24,R64-53的标准。
所以float的精度误差在1e-6;double精度误差在1e-15
判断一个单精度浮点数:则是if( fabs(a) <= 1e-6);//fabs()是对浮点数取绝对值
判断一个双精度浮点数:则是if( fabs(b) <= 1e-15 );

【规则4-3-3】不可将浮点变量用“”或“!=”与任何数字比较。
千万要留意,无论是float 还是double 类型的变量,都有精度限制。所以一定要
避免将浮点变量用“
”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。
假设浮点变量的名字为x,应当将

if (x == 0.0) // 隐含错误的比较

转化为

if ((x>=-EPSINON) && (x<=EPSINON))

其中EPSINON 是允许的误差(即精度)。

浮点数是不能直接比较大小的。原因如下:

在C++(以及其他很多编程语言)中,浮点数是以IEEE 754标准进行表示的。这种表示方法会导致浮点数运算中出现舍入误差,使得两个看似相等的浮点数在计算机内部的表示可能会有细微的差异。因此,直接比较两个浮点数是否相等是不安全的,可能会得到错误的结果。

如需要对浮点数进行比大小,我们需要定义一个很小的正数(通常设置为10的-6次方),并判断两个浮点数之差的绝对值是否小于或等于这个很小的数来判断它们是否相等。

这是一种常见且推荐的判断浮点数相等的方法。

浮点数并非真正意义上的实数,只是其在某个范围内的近似。

因此两个浮点数比较大小时,不能简单地使用大于小于号进行比较,应该判断连个浮点数差值的绝对值是否近似为0。

#include <stdio.h>
#include<math.h>#define EPS 1e-7                    //判断浮点数是否位于0的一个很小的邻域内[-EPS,EPS]内
main(){/*判断一个浮点数是否等于0*/float a;scanf("%f",&a);if(fabs(a) <= EPS)  //a=0...else if(a > EPS)    //a>0...else                //a<0.../*比较两个浮点数大小*/float a,b;scanf("%f%f",&a,&b);if(fabs(a-b) <= EPS)  //a=b...else if( (a-b) > EPS)  //a>b...else                   //a<b...}

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

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

相关文章

FreeRtos Queue(四)

本篇主要分析xQueueReceive&#xff0c;从队列中读取消息&#xff0c;读消息也是在死循环里操作的&#xff0c;大致分为两个逻辑&#xff1a; 1、队列不为空的时候的处理 2、队列为空的时候的处理 一、队列不为空 先分析下从队列中读取消息这个函数 prvCopyDataFromQueue 队…

Java进阶-IO(1)

进入java IO部分的学习&#xff0c;首先学习IO基础&#xff0c;内容如下。需要了解流的概念、分类还有其他一些如集合与文件的转换&#xff0c;字符编码问题等&#xff0c;这次先学到字节流的读写数据&#xff0c;剩余下次学完。 一、IO基础 1、背景 1.1 数据存储问题 变量…

Linux 学习笔记(8)

八、 启动引导 1 、 Linux 的启动流程 1) BIOS 自检 2) 启动 GRUB/LILO 3) 运行 Linux kernel 并检测硬件 4) 挂载根文件系统 5) 运行 Linux 系统的第一个进程 init( 其 PID 永远为 1 &#xff0c;是所有其它进程的父进程 ) 6) init 读取系统引导配置文件…

WSL2外部网络设置

1 关闭所有WSL系统 wsl --shutdown 2 打开Hyper-V管理器 3 将“虚拟交换机管理器”-> ”WSL连接类型“设置为“外部网络” 4 启动WSL系统&#xff0c;手动修改WSL网络 将WSL网络IP修改为192.168.1.9 sudo ip addr del $(ip addr show eth0 | grep inet\b | awk {print $2} |…

LeetCode:2368. 受限条件下可到达节点的数目(dfs Java)

目录 2368. 受限条件下可到达节点的数目 题目描述&#xff1a; 实现代码与解析&#xff1a; DFS 原理思路&#xff1a; 2368. 受限条件下可到达节点的数目 题目描述&#xff1a; 现有一棵由 n 个节点组成的无向树&#xff0c;节点编号从 0 到 n - 1 &#xff0c;共有 n - …

以太网模块问题及优化

在使用以太网发送摄像头数据到PC端时&#xff0c;发现了之前编写以太网发送模块的两个小问题&#xff0c;对实际使用有一定的影响&#xff0c;本文将问题指出来并进行修正。 问题一&#xff1a;为了方便设计&#xff0c;工程直接把以太网发送模块的忙闲指示信号输出作为用户端口…

Mysql与StarRocks语法上的不同

&#x1f413; 序言 StarRocks 是新一代极速全场景 MPP (Massively Parallel Processing) 数据库。StarRocks 的愿景是能够让用户的数据分析变得更加简单和敏捷。用户无需经过复杂的预处理&#xff0c;可以用StarRocks 来支持多种数据分析场景的极速分析。 &#x1f413; 语法…

Rust学习笔记:深度解析内存管理(二)

在这个信息爆炸的时代&#xff0c;学习一门新的编程语言不仅仅是为了找到一份好工作&#xff0c;更是为了打开思维的新窗口。Rust&#xff0c;作为一门注重安全、速度和并发的系统编程语言&#xff0c;正吸引着越来越多的年轻开发者的目光。今天&#xff0c;我们将一起深入探讨…

IDEA开发环境热部署

开发环境热部署 在实际的项目开发调试过程中会频繁地修改后台类文件&#xff0c;导致需要重新编译重新启动&#xff0c;整个过程非常麻烦&#xff0c;影响开发效率。Spring Boot提供了spring-boot-devtools组件&#xff0c;使得无须手动重启SpringBoot应用即可重新编译、启动项…

健身房预约系统开发 打造个性化训练计划

在快节奏的现代生活中&#xff0c;时间变得尤为宝贵。传统的健身房排队、等待不仅浪费了你的时间&#xff0c;还可能让你错过宝贵的锻炼机会。通过预约系统&#xff0c;你可以提前规划自己的健身时间&#xff0c;避免排队等待的烦恼。只需简单几步操作&#xff0c;就能预约到心…

2024最新算法:河马优化算法(HO)求解23个基准函数

一、河马优化算法 河马优化算法&#xff08;Hippopotamus optimization algorithm&#xff0c;HO&#xff09;由Amiri等人于2024年提出&#xff0c;该算法模拟了河马在河流或池塘中的位置更新、针对捕食者的防御策略以及规避方法。河马优化算法的灵感来自河马生活中观察到的三…

2.模拟问题——2.使用二维数组输出图形

用二维数组描述图形 首先要计算出整个输出的方框大小&#xff0c;从而判定相应关键循环点 #include <cstdio> char arr[1000][3000]; int main() {int h;//初始化&#xff0c;全部内部填空格while(scanf("%d",&h) ! EOF){for (int i 0; i < h; i) {f…