Scala 对于带有浮点字段的case类等于

Scala 对于带有浮点字段的case类等于,scala,hashcode,case-class,Scala,Hashcode,Case Class,是否可以使用浮点字段创建case类,如: case class SomeClass(a:Double, b:Double) 我猜自动生成的相等方法在这种情况下不起作用。 覆盖等于最佳解决方案吗 编辑: 如果重写equals是一种方法,那么我希望避免硬编码epsilon(其中epsilon的定义为=>| this.a-a | (this.a-x.a).abs

是否可以使用浮点字段创建case类,如:

case class SomeClass(a:Double, b:Double) 
我猜自动生成的相等方法在这种情况下不起作用。 覆盖等于最佳解决方案吗

编辑:

如果重写equals是一种方法,那么我希望避免硬编码epsilon(其中epsilon的定义为=>| this.a-a |
case class SomeClass(a:Double, b:Double, implicit epsilon:Double)  
我正在寻找一种方法来传递epsilon,而不是每次传递concert值 (一些“隐性”魔法)


我还提出了一个更一般的问题,如何为只有浮点字段的类定义hashcode

你说得对。如果您担心精度,则需要覆盖等于:

case class SomeClass(a:Double, b:Double)
SomeClass(2.2 * 3, 1.0) == SomeClass(6.6, 1.0)
// res0: Boolean = false

case class BetterClass(a: Double, b: Double) {
  override def equals(obj: Any) = obj match {
    case x: BetterClass =>
      (this.a - x.a).abs < 0.0001 && (this.b - x.b).abs < 0.0001   
    case _ => false
  }
}
BetterClass(2.2 * 3, 1.0) == BetterClass(6.6, 1.0)
// res1: Boolean = true
case类SomeClass(a:Double,b:Double)
SomeClass(2.2*3,1.0)=SomeClass(6.6,1.0)
//res0:Boolean=false
案例等级更好等级(a:双,b:双){
覆盖定义等于(obj:Any)=obj匹配{
案例十:BetterClass=>
(this.a-x.a).abs<0.0001&(this.b-x.b).abs<0.0001
大小写=>false
}
}
更好的等级(2.2*3,1.0)=更好的等级(6.6,1.0)
//res1:Boolean=true

啊,浮点数的乐趣

我认为用模糊比较来覆盖等式不是一个好主意。它违反了所有你通常认为理所当然的平等。假设a、b和c是一些具有模糊等式的案例类。那么有可能有a,b,c,这样a==b,b==c,但是a=c

然后考虑哈希代码的行为。如果您使用模糊等式覆盖equals,而不覆盖hashcode,则将无法在hashmap或set中使用结果对象,因为a==b,但a.hashcode=b、 哈希代码

解决此问题的最佳方法是定义一个类似=~=的运算符,该运算符除了提供equals/==之外还提供模糊比较,equals/==表示对象完全相同(至少对于scala中的不可变对象而言),这样您就可以在不更改计算结果的情况下将一个对象替换为另一个对象

如果您还希望能够通过隐式配置配置比较的精度,则会增加另一个复杂级别。下面是一个更完整的示例:

// a class to configure the comparison that will be passed to the operator 
// as an implicit value
case class CompareSettings(epsilon:Double = 0.1) extends AnyVal

// add an operator =~= to double to do a fuzzy comparions
implicit class DoubleCompareExtensions(val value:Double) extends AnyVal {
  def =~=(that:Double)(implicit settings:CompareSettings) : Boolean = {
    // this is not a good way to do a fuzzy comparison. You should have both relative
    // and absolute precision. But for an example like this it should suffice.
    (value - that).abs < settings.epsilon
  }
}

case class SomeClass(x:Double, y:Double) {
  // we need an implicit argument of type CompareSettings
  def =~=(that:SomeClass)(implicit settings:CompareSettings) =
    // the implicit argument will be automatically passed on to the operators
    this.x =~= that.x && this.y =~= that.y
}

// usage example
val x=1.0
val y=1.01

// this won't work since there is no implicit in scope
x =~= y

// define an implicit of the right type
implicit val compareSettings = CompareSettings(0.2)

// now this will work
x =~= y

// and this as well
SomeClass(1,2) =~= SomeClass(1.1,2)
//用于配置将传递给运算符的比较的类
//作为隐式值
case类比较设置(epsilon:Double=0.1)扩展了AnyVal
//将运算符=~=添加到double以进行模糊比较
隐式类DoubleCompareExtensions(val值:Double)扩展AnyVal{
def=~(that:Double)(隐式设置:比较设置):布尔={
//这不是一个进行模糊比较的好方法。你应该有两个相对值
//和绝对精度。但对于这样的例子,它应该足够了。
(value-that).abs

请注意,隐式不是类的参数,而是操作的参数。

Thx为您的示例!我已经编辑了我的问题,现在我想覆盖equals,但通过隐式机制传递0.0001。