Search code examples
scalawrapper

Double type with custom comparation in Scala


I'm migrating some old Java code to Scala which uses a "precision" threshold for comparing real values. A fragment of the already translated to Scala code would be:

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
  .
  .
  .
}

The problem with this code is that it's usage gets easily verbose, for instance:

  //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)

So I was trying to define some sort of wrapper class for the value that would allow me to use the standard operators. The idea is to be able to do:

  //Just an example of the idea
  if a == b then...
  else if a > b then...

Where a == b would be the original def equals(a: Double, b: Double): and so on

So far, I've done this:

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

which works for the comparison use case, but I must manually wrapp and unwrapp the value within the class for other usages (such as math functions or basic aritmethics). I would like to achieve this:

  val a = PrecisionDouble(3.2)
  val b: Double = math.sqrt(a)

and also be able to replace the type of the parameters in the PrecisionDouble comparison methods from def == (that: PrecisionDouble) to def == (that: Double) to be able to do the comparisons even less verbosely.

Is this somehow possible?

Edit: Scala 3.2


Solution

  • This is how to add new comparison operators in Scala 3:

    extension (d: Double)
        def === (other: Double) = CompareDouble.equals(d, other)
        def >> (other: Double) = CompareDouble.greater(d, other)
    

    You can use CrossVersion.for2_13Use3 in sbt if you need to use this in a Scala 2 project.