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
相关产品推荐
相关产品推荐

