浮点数的比较以及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

相关文章

Conda与Python venv虚拟环境的区别与使用方法详解

《Conda与Pythonvenv虚拟环境的区别与使用方法详解》随着Python社区的成长,虚拟环境的概念和技术也在不断发展,:本文主要介绍Conda与Pythonvenv虚拟环境的区别与使用... 目录前言一、Conda 与 python venv 的核心区别1. Conda 的特点2. Python v

Go语言中make和new的区别及说明

《Go语言中make和new的区别及说明》:本文主要介绍Go语言中make和new的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 概述2 new 函数2.1 功能2.2 语法2.3 初始化案例3 make 函数3.1 功能3.2 语法3.3 初始化

C# 比较两个list 之间元素差异的常用方法

《C#比较两个list之间元素差异的常用方法》:本文主要介绍C#比较两个list之间元素差异,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. 使用Except方法2. 使用Except的逆操作3. 使用LINQ的Join,GroupJoin

深度解析Spring Boot拦截器Interceptor与过滤器Filter的区别与实战指南

《深度解析SpringBoot拦截器Interceptor与过滤器Filter的区别与实战指南》本文深度解析SpringBoot中拦截器与过滤器的区别,涵盖执行顺序、依赖关系、异常处理等核心差异,并... 目录Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现

Before和BeforeClass的区别及说明

《Before和BeforeClass的区别及说明》:本文主要介绍Before和BeforeClass的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Before和BeforeClass的区别一个简单的例子当运行这个测试类时总结Before和Befor

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

Linux中的more 和 less区别对比分析

《Linux中的more和less区别对比分析》在Linux/Unix系统中,more和less都是用于分页查看文本文件的命令,但less是more的增强版,功能更强大,:本文主要介绍Linu... 目录1. 基础功能对比2. 常用操作对比less 的操作3. 实际使用示例4. 为什么推荐 less?5.

Java 关键字transient与注解@Transient的区别用途解析

《Java关键字transient与注解@Transient的区别用途解析》在Java中,transient是一个关键字,用于声明一个字段不会被序列化,这篇文章给大家介绍了Java关键字transi... 在Java中,transient 是一个关键字,用于声明一个字段不会被序列化。当一个对象被序列化时,被

解读@ConfigurationProperties和@value的区别

《解读@ConfigurationProperties和@value的区别》:本文主要介绍@ConfigurationProperties和@value的区别及说明,具有很好的参考价值,希望对大家... 目录1. 功能对比2. 使用场景对比@ConfigurationProperties@Value3. 核

Spring Boot拦截器Interceptor与过滤器Filter深度解析(区别、实现与实战指南)

《SpringBoot拦截器Interceptor与过滤器Filter深度解析(区别、实现与实战指南)》:本文主要介绍SpringBoot拦截器Interceptor与过滤器Filter深度解析... 目录Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实