如何自定义Julia语言的Set以支持浮点数近似相等判定
Julia 中实现近似相等判定浮点数Set的方法
Julia 原生的Set默认基于isequal做相等判定、基于对应值的hash做哈希索引,默认采用精确匹配规则,没有直接开箱即用的近似相等浮点数Set,但可以通过非常简单的自定义扩展或者现有生态工具实现需求,不需要从零编写完整的集合逻辑。
- 轻量化自定义实现:你可以封装一个浮点数包装类型,重载该类型的
isequal和hash方法,把相等判定规则替换为你需要的容差规则,之后就可以把该包装类型的实例放入普通Set正常使用。
示例代码(以1e-9绝对容差为例):
注意:自定义的哈希规则必须和相等判定规则严格匹配,否则会出现“判定相等但哈希不同”“哈希相同但判定不等”的逻辑冲突,直接导致Set的去重逻辑失效。struct ApproxFloat val::Float64 tol::Float64 end # 自定义相等判定:两个值的差值不超过容差即视为相等 Base.isequal(a::ApproxFloat, b::ApproxFloat) = abs(a.val - b.val) ≤ max(a.tol, b.tol) # 自定义哈希规则:按容差粒度取整后计算哈希,保证逻辑相等的实例哈希值一致 Base.hash(x::ApproxFloat, h::UInt) = hash(round(x.val / x.tol), h) # 实际使用 s = Set{ApproxFloat}() push!(s, ApproxFloat(0.5, 1e-9)) push!(s, ApproxFloat(0.50000000000000018, 1e-9)) # 该操作会被自动忽略 length(s) # 运行后返回1,符合预期 - 现成生态可用方案:如果不想自行编写包装类型,可以直接使用成熟扩展包提供的支持自定义比较器的集合结构:比如
DataStructures.jl中的RobinSet支持手动传入相等判定函数和对应的哈希函数,直接传入你需要的近似相等规则和匹配的哈希逻辑即可使用;如果你的场景是处理浮点数计算的固有舍入误差,也可以使用IntervalArithmetic.jl的区间类型做集合元素,区间存在重叠即判定为重复,天然适配浮点数误差场景。 - 关键避坑点:绝对不要直接全局重写
Float64类型的isequal和hash方法,这种修改会污染全局环境,破坏所有依赖默认浮点数相等逻辑的代码,会引发极难排查的隐性bug,所有自定义逻辑都要限定在自定义包装类型或者指定容器的参数范围内。
内容的提问来源于stack exchange,提问作者user888379
相关产品推荐
相关产品推荐

