如何比较Scala中的浮点值?

Iva*_*van 22 floating-point double comparison scala

据我所知,精确比较没有多大意义浮点值什么是意在0.0001居然能像0.0001000 ...... 0001 ......我应该实现自己的比较功能,以指定的精度或有一个共同的做法吗?

我曾经使用过以下的C#(我怀疑它仍然是错误的,因为Double值可能无法代表0.0001,甚至设置为常量(正如Michael Borgwardt 在此解释的那样)):

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;
}
Run Code Online (Sandbox Code Playgroud)

我应该在Scala中做些什么吗?

Kim*_*bel 29

是的,你可以做与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
Run Code Online (Sandbox Code Playgroud)


Kim*_*bel 11

或者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
}
Run Code Online (Sandbox Code Playgroud)


Rom*_*kov 7

使用来自scalautils的容差

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

val result = 2.000001
Run Code Online (Sandbox Code Playgroud)

结果:Double = 2.000001

result === 2.0 +- .001
Run Code Online (Sandbox Code Playgroud)

res0:Boolean = true

result === 2.0 +- .000000001
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)