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

2024-01-31 00:32

本文主要是介绍『踩坑记录』浮点数的比较以及abs和fabs的区别,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在C语言中,我们知道浮点数的存储方式是IEEE(电气和电子工程协会)规定的,使用三个部分表示一个浮点数:符号位、有效数字和指数位。

浮点数的比较

任意一个二进制浮点数V可以表示成下面的形式:

  • V = ( − 1 ) S ∗ M ∗ 2 E V = (-1)^S*M*2^E V=(1)SM2E,S为符号位,M为有效数字,E为指数位。

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

下面,我们来看一个例子

#include <stdio.h>
#include <stdlib.h>
#include <math.h>int main(){float n = 1 - 0.0000001;// 理论上是相同的if (n == 0.9999999){printf("hello, world!\n");}return 0;
}

运行结果如下
在这里插入图片描述
从上述结果可以看出,程序判断二者是不相等的,这是因为float表示的精度达不到这么高
我们将程序修改一下

#include <stdio.h>
#include <stdlib.h>
#include <math.h>int main(){float n = 1 - 0.0000001;if (fabs(n - 0.9999999) < 1e-6){printf("hello, world!\n");}return 0;
}

运行结果如下
在这里插入图片描述
结论

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

abs和fabs的区别

首先,这两个函数在C语言中的区别

  • abs是针对整数求绝对值定义在stdlib.h头文件中
    在这里插入图片描述
  • fabs是针对浮点数求绝对值fabs定义在math.h头文件中。
    在这里插入图片描述

我们来看下面一个例子

#include <stdio.h>
#include <stdlib.h>
#include <math.h>int main(){// 使用abs求一个整数的绝对值printf("abs(-3): %d\n\n", abs(-3));// 使用fabs求一个整数的绝对值printf("fabs(-3)(%%d): %d\n", fabs(-3));printf("fabs(-3)(%%f): %f\n\n", fabs(-3));// 使用fabs求一个浮点数的绝对值printf("fabs(-3.14): %f\n\n", fabs(-3.14));// 使用abs求一个浮点数的绝对值printf("abs(-3.14)(%%d): %d\n", abs(-3.14));printf("abs(-3.14)(%%f): %f\n", abs(-3.14));return 0;
}

运行结果如下
在这里插入图片描述
从上述运行结果可以看出,使用abs求浮点数的绝对值是有问题的,使用fabs求整数的绝对值也是有问题的,所以在C语言中求浮点数的时候一定要选对函数


下面,我们来看一下这两个函数在C++中的区别
在这里插入图片描述
在这里插入图片描述
上述官方文档中可以看出,二者基本没有区别

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



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

相关文章

MyBatis中$与#的区别解析

《MyBatis中$与#的区别解析》文章浏览阅读314次,点赞4次,收藏6次。MyBatis使用#{}作为参数占位符时,会创建预处理语句(PreparedStatement),并将参数值作为预处理语句... 目录一、介绍二、sql注入风险实例一、介绍#(井号):MyBATis使用#{}作为参数占位符时,会

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Javaee多线程之进程和线程之间的区别和联系(最新整理)

《Javaee多线程之进程和线程之间的区别和联系(最新整理)》进程是资源分配单位,线程是调度执行单位,共享资源更高效,创建线程五种方式:继承Thread、Runnable接口、匿名类、lambda,r... 目录进程和线程进程线程进程和线程的区别创建线程的五种写法继承Thread,重写run实现Runnab

C++中NULL与nullptr的区别小结

《C++中NULL与nullptr的区别小结》本文介绍了C++编程中NULL与nullptr的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编... 目录C++98空值——NULLC++11空值——nullptr区别对比示例 C++98空值——NUL

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中集成RabbitMQ的实战记录

《在SpringBoot中集成RabbitMQ的实战记录》本文介绍SpringBoot集成RabbitMQ的步骤,涵盖配置连接、消息发送与接收,并对比两种定义Exchange与队列的方式:手动声明(... 目录前言准备工作1. 安装 RabbitMQ2. 消息发送者(Producer)配置1. 创建 Spr

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

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

k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)

《k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)》本文记录在K8s上运行的MySQL/MariaDB备份方案,通过工具容器执行mysqldump,结合定时任务实... 目录前言一、获取需要备份的数据库的信息二、备份步骤1.准备工作(X86)1.准备工作(arm)2.手