我正在将一些旧的 Java 代码迁移到 Scala,它使用“精度”阈值来比较实际值。已翻译为 Scala 代码的片段如下:
object CompareDouble {
private val EPSILON = 0.00001
def equals(a: Double, b: Double): Boolean = a == b || Math.abs(a - b) < EPSILON
def greater(a: Double, b: Double): Boolean = a - b > EPSILON
.
.
.
}
这段代码的问题在于它的用法很容易变得冗长,例如:
//In an interval overlap comparison
CompareDouble.lessEquals(low1, low2) && CompareDouble.lessEquals(low2, up1) ||
CompareDouble.lessEquals(low1, up2) && CompareDouble.lessEquals(up2, up1) ||
CompareDouble.lessEquals(low2, low1) && CompareDouble.lessEquals(low1, up2) ||
CompareDouble.lessEquals(low2, up1) && CompareDouble.lessEquals(up1, up2)
所以我试图为允许我使用标准运算符的值定义某种包装类。这个想法是能够做到:
//Just an example of the idea
if a == b then...
else if a > b then...
其中
a == b
是原始的 def equals(a: Double, b: Double):
等等
到目前为止,我已经做到了:
class PrecisionDouble(var wrapp: Double) {
// PrecissionDouble.EPSILON refers to a field in this class' companion object
def == (that: PrecisionDouble): Boolean = wrapp == that.wrapp || Math.abs(wrapp - that.wrapp) < PrecisionDouble.EPSILON
def < (that: PrecisionDouble): Boolean = (that.wrapp - wrapp) > PrecisionDouble.EPSILON
这适用于比较用例,但我必须手动包装和解开类中的值以用于其他用途(例如数学函数或基本 aritmethics)。我想实现这个目标:
val a = PrecisionDouble(3.2)
val b: Double = math.sqrt(a)
并且还能够将 PrecisionDouble 比较方法中的参数类型从
def == (that: PrecisionDouble)
替换为 def == (that: Double)
,以便能够更加简洁地进行比较。
这有可能吗?
最简单的可能是使用一组不同的运算符:
object Precision {
implicit class D(val d: Double) extends AnyVal {
def === (other: Double) = CompareDouble.equals(d, other)
def >> (other: Double) = CompareDouble.grater(d, other)
// etc.
}
}
import Precision._
println (1.41 === math.sqrt(2))
或者,您可以在
Double
和 PrecisionDouble
之间定义隐式转换,但我认为,这是较差的,因为,如果运算符相同,则在大多数情况下转换都不会自动发生。