You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中如何对浮点数和复数实现近似结构化模式匹配

浮点数match/case近似匹配实现

Python原生浮点数存在二进制存储舍入误差,以下精确等值判断均会返回不符合直觉的结果:

>>> sum([0.1] * 10) == 1.0
False

>>> 1.1 + 2.2 == 3.3
False

>>> from math import sin, radians, sqrt
>>> sin(radians(45)) == sqrt(2) / 2
False

常规规避方案是使用math.isclose()(原生浮点数)或cmath.isclose()(复数)做近似等值判断,但match/case语句的字面量分支默认使用==做精确匹配,直接写case 3.3无法命中1.1 + 2.2的计算结果,可以通过以下两种方案实现近似匹配。

方案1:分支守卫(适配少量分支场景)

match/case支持为分支添加if守卫条件,仅当模式匹配和守卫条件同时满足时才进入对应分支,直接在守卫中调用isclose即可实现近似判断:

import math

match 1.1 + 2.2:
    case val if math.isclose(val, 3.3):
        print('hit!')  # 正常触发

多分支场景下可以为每个分支单独配置公差,灵活性极高:

import math

val = 1.1 + 2.2
match val:
    case x if math.isclose(x, 0, abs_tol=1e-9):
        print("匹配近0值")
    case x if math.isclose(x, 3.3, rel_tol=1e-6):
        print("匹配3.3,使用宽松相对公差")
    case _:
        print("无匹配项")

方案2:自定义近似匹配类(适配多分支场景)

Python类模式匹配会通过__eq__方法做等值校验,可以把近似判断逻辑封装到自定义类中,实现和原生字面量一致的简洁写法:

import math
import cmath

class Approx:
    __match_args__ = ("expected",)  # 支持位置参数传参,简化写法
    def __init__(self, expected, rel_tol=1e-9, abs_tol=0.0):
        self.expected = expected
        self.rel_tol = rel_tol
        self.abs_tol = abs_tol
    
    def __eq__(self, actual):
        # 自动适配复数场景
        judge = cmath.isclose if isinstance(actual, complex) else math.isclose
        return judge(actual, self.expected, rel_tol=self.rel_tol, abs_tol=self.abs_tol)

使用时直接在case后调用即可,不需要额外写守卫:

match 1.1 + 2.2:
    case Approx(3.3):
        print('hit!')  # 正常触发

# 自定义公差直接传参即可
match 1.1 + 2.2:
    case Approx(3.3, rel_tol=1e-6):
        print('hit with loose tolerance!')

避坑提示

  • 禁止通过猴子补丁修改float.__eq__实现全局近似匹配,这会破坏Python数值系统的逻辑一致性,引发极难排查的隐性bug。
  • 如果匹配目标是numpy数组、pandas数值等第三方库数值类型,只需把类中isclose替换为对应库提供的近似判断方法(如numpy.isclose)即可,适配逻辑完全一致。

内容的提问来源于stack exchange,提问作者Raymond Hettinger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 21:36:18