一篇文章带你了解C语言浮点数之间的比较规则

目录
  • 你认为这段代码输出什么?
  • 为什么不等于呢?
  • 应该怎么解决?
    • 那么怎么判断两个浮点数 f1 和 f2 相等呢。
      • 伪代码
      • 可以简化为 >>
  • 怎么判断浮点数等于0?
    • 还有一个问题
  • 总结

你认为这段代码输出什么?

int main()
{
	float f1 = 1.1;
	float f2 = 2.2;
	if (f2 - 1.1 == f1)
		printf("等于");
	else
		printf("不等于");
	return 0;
}

答案是不等于。

为什么不等于呢?

因为在C语言中浮点数是存在精度损失的,有可能比原来的数大,也有可能小。 在下图所示,f1在打印小数点后30位时就能很明显的看出存在精度损失。

应该怎么解决?

浮点数不能直接用 == 号比较。那么应该怎么比较呢。

这里要引出精度这个概念,精度可以理解为引发一个浮点数发生改变的最小值。

当一个浮点数加上精度或者减去精度,都不等于该数本身。

精度可以是自己定义的,也可以用C语言自带的,它定义在 float.h 头文件中。

#define FLT_EPSILON      1.192092896e-07F        // smallest such that 1.0+FLT_EPSILON != 1.0
#define DBL_EPSILON      2.2204460492503131e-016 // smallest such that 1.0+DBL_EPSILON != 1.0

FLT_EPSILON 为float类型的默认精度,DBL_EPSILON 为double类型的精度。

那么怎么判断两个浮点数 f1 和 f2 相等呢。

虽然两个浮点数存在精度上的误差,但这个误差非常小,只要(f2 - f1)这个差值在负精度到正精度的区间内,就可以认为它们相等。

如图,它们的差值必须在 (-XXX_EPSILON,XXX_EPSILON) 这个区间内,才能说明它们相等。

伪代码

if(f2 - f1) > -XXX_EPSILON  && (f2 - f1)< XXX_EPSION){相等;}

可以简化为 >>

if (fabs(f2 - f1) < XXX_EPSILON) //fabs函数求绝对值,在math.h头文件中{相等;}

怎么判断浮点数等于0?

这个浮点数的绝对值小于精度,可以认为这个数为0。

if (fabs(f1) < XXX_EPSILON)
{
	//f1为0
}

还有一个问题

// 判断f1为0的条件 < 能换成 <= 吗

if (fabs(f1) < XXX_EPSILON) ->>  if (fabs(f1) <= XXX_EPSILON)

0的性质:任何数加上0,都等于它本身。
而上述也讲了精度的定义为浮点数加上XXX_ESILON 都会发生改变,如果 f1 可以等于 XXX_ESILON ,不是说一个浮点数加上0会发生改变吗,这明显不符合0的性质。所以是开区间,只能是 < 。

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • C语言中魔性的float浮点数精度问题

    从一个问题引入 如果你以前接触过C语言,那么对下面的这段代码一定很熟悉: #include <stdio.h> int main(void) { float f_num1 = 21.75; float f_num2 = 13.45; printf("f_num1 = %f\n", f_num1); printf("f_num2 = %f\n", f_num2); printf("f_num1 + f_num2 = %f\n", f_n

  • Java正确比较浮点数的方法

    看下面这段代码,将 d1 和 d2 两个浮点数进行比较,输出的结果会是什么? double d1 = .1 * 3; double d2 = .3; System.out.println(d1 == d2); 按照正常逻辑来看,d1经过计算之后的结果应该是0.3,最后打印的结果应该是 true,对吧?但是运行一下就会发现结果并不是 true 而是 false . 输出一下 d1,发现得到的答案不是想象中的 0.3 而是 0.30000000000000004,所以和 d2 进行比较结果自然是 f

  • java.math包下计算浮点数和整数的类的实例

    java.math包提供了java中的数学类.包括基本的浮点库.复杂运算以及任意精度的数据运算 提供用于执行任意精度整数算法 (BigInteger) 和任意精度小数算法 (BigDecimal) 的类.BigInteger 除提供任意精度之外,它类似于 Java 的基本整数类型,因此在 BigInteger 上执行的操作不产生溢出,也不会丢失精度.除标准算法操作外,BigInteger 还提供模 (modular) 算法.GCD 计算.基本 (primality) 测试.素数生成.位处理以及一

  • C语言数据(整数、浮点数)在内存中的存储

    本篇主要讨论:整数.浮点数在内存中是怎么保存的! 数据类型详细介绍 在前面C语言基础概览中,已经提到过了基本的C语言内置类型,但C语言的数据类型有无数种~ 但是可以把这些类型分为几个大类: 类型的归类: 存整数的 char,short,int,long,long long及所配套的unsigned,int*,int[]- 2.存浮点数的 float,double,float[]- 结构体(结构体在内存中的存储后面在进行讨论~) 整数在内存种的存储: 1.字节序 2.补码 内存窗口 调试模式下的内

  • C语言菜鸟基础教程之单精度浮点数与双精度浮点数

    上节课 简单介绍了浮点数.计算机程序中的浮点数分为单精度浮点数和双精度浮点数. 单精度和双精度精确的范围不一样. 计算机里的最基本的存储单位用位(bit)来表示.bit只能用来存储0或1. 稍大一点的单位是字节(Byte,简写为B). 再大一级的是千字节(kilo Bytes),用k来表示. 再大一级的单位是兆字节(Mega Bytes),用M来表示.一张照片的大小通常为1~3M. 再大一级的单位为G.一部高清电影的大小通常为1~2G. 再大一级的单位为T. 换算关系为: 1B = 8bit 1

  • 一篇文章带你了解C语言浮点数之间的比较规则

    目录 你认为这段代码输出什么? 为什么不等于呢? 应该怎么解决? 那么怎么判断两个浮点数 f1 和 f2 相等呢. 伪代码 可以简化为 >> 怎么判断浮点数等于0? 还有一个问题 总结 你认为这段代码输出什么? int main() { float f1 = 1.1; float f2 = 2.2; if (f2 - 1.1 == f1) printf("等于"); else printf("不等于"); return 0; } 答案是不等于. 为什么不

  • 一篇文章带你入门C语言:操作符

    目录 操作符 分类 算术操作符 移位操作符 整数存储规则 左右移位规则 赋值操作符 单目操作符 取地址操作符& 解引用操作符* 类型长度操作符sizeof 按位取反操作符~ ++ -- 操作符 强制类型转换操作符(type) 关系操作符= 逻辑操作符 短路运算 条件操作符 逗号表达式 下标引用.函数调用和结构成员 下标引用操作符[] 函数调用操作符() 结构成员操作符. -> 结构体定义 结构体使用 结构体地址 表达式求值 隐式类型转换 整型提升 如何整型提升 有符号数 无符号数 算术转换

  • 一篇文章带你了解C语言:入门基础(2)

    目录 操作符 算术操作符 移位操作符 位操作符 单目操作符 逻辑反操作! 操作符++,-- 逻辑操作符 条件操作符 逗号表达式 常见关键字 typedef extern static 修饰局部变量 修饰全局变量和函数 其它 #define定义常量和宏 定义常量 定义宏 指针 内存单元 指针变量 &取地址操作符,*解引用操作符 类型所占空间 结构体 定义结构体 使用结构体变量 总结 本节将结束对初识C语言的概述,只追求大概,不求精细. 本节包括的内容有操作符,常见关键字,#define定义常量和宏

  • 一篇文章带你了解C语言--数据的储存

    目录 前言 数据类型介绍 类型的基本归类 整形在内存中的存储 原码.反码.补码 大小端介绍 浮点型在内存中的存储 前言 前面我们学习了C语言的一些基本知识和基础的语法,想必大家对C语言都有了自己的认识. 当然只是学习这些知识还是不够的,我们需要进行更加深入的学习. 从本章开始,我们将进行C语言进阶阶段的学习,所以难度会有所增加. 数据类型介绍 前面我们已经学习了基本的内置类型: char //字符数据类型 short //短整型 int //整形 long //长整型 long long //更

  • 一篇文章带你了解C语言操作符

    目录 一.操作符分类 二.算术操作符 三.移位操作符 1.左移操作符 2.右移操作符 2.1算术移位 2.2逻辑移位 四.位操作符 1.按位与 2.按位或 3.按位异或 4.一道练习题 五.赋值操作符 1.赋值操作符(=)是一个很棒的操作符,他可以让你得到一个你之前不满意的值.也就是你可以对其重新赋值. 2.赋值操作符可以连续使用 3.复合赋值符 六.单目操作符 1.逻辑反操作 2.取地址 3.sizeof 4.++和--运算符 4.1前置++和-- 4.2后置++和-- 七.关系操作符 八.逻

  • 一篇文章带你入门C语言:函数

    目录 函数 定义 库函数 定义 介绍 Example 1 strcpy Example 2 memset 自定义函数 Example 1 Example 2 两数交换 链式访问 Example 1 函数声明 函数递归 Example 1 Example 2 函数迭代 Example 3 Example 4 总结 函数 定义 程序里的函数又被叫做子程序,他作为一个大型程序的部分代码,有一或多个语句项组成.函数负责完成某项特定任务,提供了对过程的封装和对细节的隐藏,这样的代码通常会被集成为软件库.

  • 一篇文章带你入门C语言数据结构:绪论

    目录 绪论 什么是数据结构? Example 1 讨论 Example 2 Example 3 Example 4 总结 绪论 什么是数据结构? 不同于计算机操作培训,注意与程序设计的区别. Example 1 求n个数的最大值.次最大值. //1.遍历 - 最朴素的方法 int main() { int arr[10] = { 22,334,552,1,4,6,78,23,55,98 }; int i = 0; int temp = 0; int max1 = arr[0]; int max2

  • 一篇文章带你了解C语言:入门基础

    目录 C语言本身特点 数据类型 常量变量 变量分类 使用小建议 生命周期作用域 常量分类及其特点 字符串+转义字符+注释 字符串 转义字符 两种注释 选择循环语句 函数 数组 总结 闲话少说,先上思维导图. 如图所示,现在还是初识C语言的第一部分,本次只介绍了C语言本身特点,数据类型,常量变量,字符串转义字符注释,选择循环语句,函数,数组. 接下来请和我一起粗略地探讨其中内涵所在. C语言本身特点 这是C语言的定义: C语言是一门通用计算机编程语言,广泛应用于底层开发.C语言的设计目标是提供一种

  • 一篇文章带你使用C语言编写内核

    目录 gcc 命令 文件头 将内核载入内存 总结 gcc 命令 使用 gcc 编译 c语言 -c 编译.汇编到目标代码,不进行链接,也就是直接生成目标文件 -o 将输出的文件以指定文件名来储存,有同名文件存在时直接覆盖 gcc -c -o kernel/main.o kernel/main.c 编译:编译号之后只是个目标文件,也称为待重定位文件,重定位指的是文件里面所用的符号还没有安排地址,这些符号的地址需要将来与其他目标文件"组成"一个可执行文件时再重新定位(编排地址〉,这里的符号就

  • 一篇文章带你了解C语言的一些重要字符串与内存函数

    目录 一.字符串函数 1. 求字符串长度的strlen 2.比较字符串大小的strcmp 3.复制字符串的strcpy 4.追加字符串的strcat 5.查找字符串函数的strstr 二.内存函数 1.复制 memcpy,memmove 2.比较 memcmp 总结 一.字符串函数 1. 求字符串长度的strlen size_t strlen ( const char * str ); 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '

随机推荐