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


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;
    else
        cout << "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
        ...
    
}
  • 15
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值