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

Scala 3.2中自定义精度Double类型的比较与隐式转换实现

解决Scala 3.2中PrecisionDouble的自动适配与原生Double比较问题

一、核心实现思路

借助Scala 3的隐式转换和扩展方法特性,让PrecisionDouble既能自动与原生Double互转、无缝对接标准数学函数,又能保留基于EPSILON的浮点比较逻辑,彻底摆脱手动拆装箱的繁琐。

二、具体代码实现

1. 定义PrecisionDouble核心类

封装EPSILON比较逻辑,重写标准比较运算符:

case class PrecisionDouble(value: Double, epsilon: Double = 1e-9) {
  // 基于阈值的相等判断
  def ==(other: PrecisionDouble): Boolean = math.abs(value - other.value) <= epsilon
  def !=(other: PrecisionDouble): Boolean = !this.==(other)

  // 大小比较逻辑
  def >(other: PrecisionDouble): Boolean = value - other.value > epsilon
  def >=(other: PrecisionDouble): Boolean = this.>(other) || this.==(other)
  def <(other: PrecisionDouble): Boolean = other.value - value > epsilon
  def <=(other: PrecisionDouble): Boolean = this.<(other) || this.==(other)
}

2. 添加隐式转换实现自动互转

通过隐式转换消除手动拆装箱操作,让PrecisionDouble和原生Double可以自动转换:

object PrecisionDouble {
  // 原生Double转PrecisionDouble(默认使用1e-9作为阈值)
  implicit def doubleToPrecision(d: Double): PrecisionDouble = PrecisionDouble(d)
  // PrecisionDouble转原生Double
  implicit def precisionToDouble(pd: PrecisionDouble): Double = pd.value

  // 自定义阈值的转换方法(按需使用)
  def withEpsilon(d: Double, eps: Double): PrecisionDouble = PrecisionDouble(d, eps)
}

3. 扩展方法对接标准数学函数

用扩展方法让PrecisionDouble直接调用Math库方法,无需手动拆箱:

extension (pd: PrecisionDouble) {
  def sin: Double = math.sin(pd.value)
  def cos: Double = math.cos(pd.value)
  def sqrt: PrecisionDouble = PrecisionDouble(math.sqrt(pd.value), pd.epsilon)
  // 可按需添加tan、log、pow等其他数学方法
}

4. 原生Double直接比较的实现

借助隐式转换,当PrecisionDouble与原生Double比较时,Double会自动转为PrecisionDouble,直接使用重写后的比较逻辑:

// 使用示例
import PrecisionDouble._

val pd1 = PrecisionDouble(0.1 + 0.2)
val pd2 = PrecisionDouble(0.3)
println(pd1 == pd2) // 输出true

// 和原生Double直接比较
println(pd1 == 0.3) // 输出true
println(pd1 > 0.2) // 输出true

// 自动适配算术运算
val sum = pd1 + pd2 // 自动转为Double运算,结果为Double
val pdSum = PrecisionDouble(sum)
println(pdSum == 0.6) // 输出true

// 直接调用数学函数
val sqrtPd = pd2.sqrt
println(sqrtPd == math.sqrt(0.3)) // 输出true

三、可选扩展:保留PrecisionDouble的算术运算

如果希望算术运算后仍返回PrecisionDouble而非原生Double,可以扩展算术运算符:

extension (pd: PrecisionDouble) {
  def +(other: PrecisionDouble): PrecisionDouble = 
    PrecisionDouble(pd.value + other.value, math.max(pd.epsilon, other.epsilon))
  def -(other: PrecisionDouble): PrecisionDouble = 
    PrecisionDouble(pd.value - other.value, math.max(pd.epsilon, other.epsilon))
  // 同理可扩展*、/等运算符,阈值取两者中的最大值保证精度
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 03:15:06