如何判断c语言两个浮点数相等,在Python中判断两个浮点数的相等

在Python中判断两个浮点数的相等

2021-05-11 21:52:18 +08

字数:1025

标签:

Python

如何判断两个浮点数是否相等?

这是一个所有编程语言都有的小坑。

在其它编程语言,使用==来判断是绝对的大忌,因为浮点数在低位会丢失精度。

无论float还是double都精度有限,只是精度不同。

Python中虽然统一了float和double,但不可避免地仍然有这个问题。

精度丢失 ¶

>>> 0.1 + 0.2

0.30000000000000004

简单地说,$0.1$在二进制中,是一个无限循环小数$0.0\dot{0}\dot{0}\dot{1}\dot{1}$。

这虽然违反了习惯十进制的人类直觉,但确实是真实存在。

就像$1 \over 3$在十进制中是无限循环小数$0.\dot{3}$一样,而$1 \over 3$在三进制中,表示为$0.1$。

计算机在处理小数时,是通过二进制寄存器来存储和计算,长度有限,因此会丢失无限循环小数低位的数字。

所以,不同进制在转换过程中,可能存在失真。

表现为,小数的低位不准。

那么浮点数的精度如何?

>>> import sys

>>> sys.float_info.epsilon

2.220446049250313e-16

按照C99的float.h,精度大概是这个情况。

前面0.1 + 0.2的那个尾巴是4e-17,小于2.22e-16,在精度允许的范围内。

大部分语言的浮点数遵循这个标准。

所以,如果两个浮点数的差,小于这个精度,就可以认为两个数相等。

def eq(a: float, b: float) -> bool:

return abs(a - b) < sys.float_info.epsilon

这也是大部分语言判断浮点数相等的手法。

有时,我们也会容忍epsilon大一点。

math.isclose ¶

在Python 3.5以后,通常使用math.isclose来判断两个浮点数相等。

>>> import math

>>> math.isclose(0.1 + 0.2, 0.3)

通过查阅文档和测试,发现isclose函数的实现相当于以下代码:

def isclose(a, b, rel_tol=1e-09, abs_tol=0):

return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

相对精度rel_tol普遍适用的,相当于默认保留9位有效数字。

但有时也会有一些反直觉的现象:

>>> math.isclose(1e10, 1e10 + 1)

True

某些领域,或者计算机日常业务的多数场景,使用abs_tol会更符合直觉一些。

>>> math.isclose(1e10, 1e10 + 1, rel_tol=0, abs_tol=0.001)

False

>>> math.isclose(1, 1.01, rel_tol=0, abs_tol=0.001)

False

>>> math.isclose(1, 1.001, rel_tol=0, abs_tol=0.001)

True

不要直接利用== ¶

在Python中,==在判断浮点数的时候,看上去好像实现了math.isclose(a, b, rel_tol=1e-16, abs_tol=0):

>>> 1.0000000000001 == 1

False

>>> 1.00000000000001 == 1

True

其实并没有。因为:

>>> 1.0000000000001

1.0000000000001

>>> 1.00000000000001

1.0

1 + 1e-16只是精度丢失了而已。

Python判断两个浮点数是否相等,底层仍然是C语言实现的,判断的是寄存器的相等性。

MyFloat ¶

但是,通过重载==,可以实现math.isclose的功能,看上去简洁一些。

class MyFloat(float):

def __eq__(self, other):

return math.isclose(self, other, rel_tol=0, abs_tol=0.001)

在使用时:

>>> a == MyFloat(0)

>>> a

0.0

>>> a == 0.001

True

>>> 0.001 == a

True

也只是看上去简洁。

参考 ¶

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值