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

2024-03-02 15:52
文章标签 浮点数 比较 区别 abs fabs

本文主要是介绍浮点数的比较以及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...}

这篇关于浮点数的比较以及abs和fabs的区别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/766651

相关文章

Vue和React受控组件的区别小结

《Vue和React受控组件的区别小结》本文主要介绍了Vue和React受控组件的区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录背景React 的实现vue3 的实现写法一:直接修改事件参数写法二:通过ref引用 DOMVu

JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法

《JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法》:本文主要介绍JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法,每种方法结合实例代码给大家介绍的非常... 目录引言:为什么"相等"判断如此重要?方法1:使用some()+includes()(适合小数组)方法2

Go之errors.New和fmt.Errorf 的区别小结

《Go之errors.New和fmt.Errorf的区别小结》本文主要介绍了Go之errors.New和fmt.Errorf的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考... 目录error的基本用法1. 获取错误信息2. 在条件判断中使用基本区别1.函数签名2.使用场景详细对

Redis中哨兵机制和集群的区别及说明

《Redis中哨兵机制和集群的区别及说明》Redis哨兵通过主从复制实现高可用,适用于中小规模数据;集群采用分布式分片,支持动态扩展,适合大规模数据,哨兵管理简单但扩展性弱,集群性能更强但架构复杂,根... 目录一、架构设计与节点角色1. 哨兵机制(Sentinel)2. 集群(Cluster)二、数据分片

Python如何实现高效的文件/目录比较

《Python如何实现高效的文件/目录比较》在系统维护、数据同步或版本控制场景中,我们经常需要比较两个目录的差异,本文将分享一下如何用Python实现高效的文件/目录比较,并灵活处理排除规则,希望对大... 目录案例一:基础目录比较与排除实现案例二:高性能大文件比较案例三:跨平台路径处理案例四:可视化差异报

一文带你迅速搞懂路由器/交换机/光猫三者概念区别

《一文带你迅速搞懂路由器/交换机/光猫三者概念区别》讨论网络设备时,常提及路由器、交换机及光猫等词汇,日常生活、工作中,这些设备至关重要,居家上网、企业内部沟通乃至互联网冲浪皆无法脱离其影响力,本文将... 当谈论网络设备时,我们常常会听到路由器、交换机和光猫这几个名词。它们是构建现代网络基础设施的关键组成

redis和redission分布式锁原理及区别说明

《redis和redission分布式锁原理及区别说明》文章对比了synchronized、乐观锁、Redis分布式锁及Redission锁的原理与区别,指出在集群环境下synchronized失效,... 目录Redis和redission分布式锁原理及区别1、有的同伴想到了synchronized关键字

MySQL中比较运算符的具体使用

《MySQL中比较运算符的具体使用》本文介绍了SQL中常用的符号类型和非符号类型运算符,符号类型运算符包括等于(=)、安全等于(=)、不等于(/!=)、大小比较(,=,,=)等,感兴趣的可以了解一下... 目录符号类型运算符1. 等于运算符=2. 安全等于运算符<=>3. 不等于运算符<>或!=4. 小于运

JAVA覆盖和重写的区别及说明

《JAVA覆盖和重写的区别及说明》非静态方法的覆盖即重写,具有多态性;静态方法无法被覆盖,但可被重写(仅通过类名调用),二者区别在于绑定时机与引用类型关联性... 目录Java覆盖和重写的区别经常听到两种话认真读完上面两份代码JAVA覆盖和重写的区别经常听到两种话1.覆盖=重写。2.静态方法可andro

C++中全局变量和局部变量的区别

《C++中全局变量和局部变量的区别》本文主要介绍了C++中全局变量和局部变量的区别,全局变量和局部变量在作用域和生命周期上有显著的区别,下面就来介绍一下,感兴趣的可以了解一下... 目录一、全局变量定义生命周期存储位置代码示例输出二、局部变量定义生命周期存储位置代码示例输出三、全局变量和局部变量的区别作用域