Как сравнить значения с плавающей точкой в ​​Scala? - PullRequest
22 голосов
/ 05 декабря 2011

Насколько я знаю, точное сравнение не имеет большого смысла со значениями с плавающей запятой, поскольку то, что должно быть 0,0001, может фактически быть чем-то вроде 0,0001000 ... 0001 ... Должен ли я реализовать свою собственную функцию сравнения, чтобы указать Точность или есть распространенная практика для этого?

Раньше я использовал следующее с C # (что, я подозреваю, все еще неверно, поскольку значение Double, вероятно, вообще не может представлять 0,0001, даже если задано как константа (как объяснил Майкл Боргвардт здесь * 1004) *)):

public static bool AlmostEquals(this double x, double y, double precision = 0.0001)
{
  if (precision < 0.0)
    throw new ArgumentException();

  return Math.Abs(x - y) <= precision;
}

Должен ли я сделать что-то похожее в Scala?

Ответы [ 3 ]

29 голосов
/ 05 декабря 2011

Да, вы можете сделать то же самое, что и в Java. Вы также можете использовать некоторые интересные функции Scala и превратить класс Double в метод ~ =, который принимает неявный параметр точности, который нужно указывать только один раз.

scala> case class Precision(val p:Double)
defined class Precision

scala> class withAlmostEquals(d:Double) {
  def ~=(d2:Double)(implicit p:Precision) = (d-d2).abs <= p.p
}
defined class withAlmostEquals

scala> implicit def add_~=(d:Double) = new withAlmostEquals(d)
add_$tilde$eq: (d: Double)withAlmostEquals

scala> 0.0~=0.0
<console>:12: error: could not find implicit value for parameter p: Precision
              0.0~=0.0
                 ^

scala> implicit val precision = Precision(0.001)
precision: Precision = Precision(0.001)

scala> 0.0 ~= 0.00001
res1: Boolean = true
11 голосов
/ 15 сентября 2012

Или с 2.10 ...

case class Precision(p:Double)

implicit class DoubleWithAlmostEquals(val d:Double) extends AnyVal {
  def ~=(d2:Double)(implicit p:Precision) = (d - d2).abs < p.p
}
7 голосов
/ 30 июня 2015

Использовать допуск от scalautils

import org.scalautils._
import TripleEquals._
import Tolerance._

val result = 2.000001

результат: Double = 2.000001

result === 2.0 +- .001

res0: Boolean = true

result === 2.0 +- .000000001

res1: Boolean = false

Обновление: для Scala 2.11

import org.scalatest._
import org.scalatest.Matchers._
val r = 4
val rr = (r === 2 +- 1)

r: Int = 4 
rr: Boolean = false
...