How to compare floating-point numbers in Scala

Scala FAQ: I need to compare two floating-point numbers in Scala, but as in some other programming languages, two floating-point numbers that should be equivalent may not be; how do I comparison floating-point numbers?

Solution

As in Java and many other languages, you solve this problem by creating a method that lets you specify the precision for your comparison. The following Scala “approximately equals” method demonstrates the approach:

def ~=(x: Double, y: Double, precision: Double) = {
    if ((x - y).abs < precision) true else false
}

You can use this method like this:

scala> val a = 0.3
a: Double = 0.3

scala> val b = 0.1 + 0.2
b: Double = 0.30000000000000004

scala> ~=(a, b, 0.0001)
res0: Boolean = true

scala> ~=(b, a, 0.0001)
res1: Boolean = true

Discussion

When you begin working with floating-point numbers in programming, you quickly learn that 0.1 plus 0.1 is 0.2:

scala> 0.1 + 0.1
res2: Double = 0.2

But 0.1 plus 0.2 isn’t exactly 0.3:

scala> 0.1 + 0.2
res3: Double = 0.30000000000000004

This subtle inaccuracy makes comparing two floating-point numbers a real problem:

scala> val a = 0.3
a: Double = 0.3

scala> val b = 0.1 + 0.2
b: Double = 0.30000000000000004

scala> a == b
res4: Boolean = false

As a result, you end up writing your own functions to compare floating-point numbers with a precision (or tolerance).

As you saw in Recipe 1.11 of the Scala Cookbook, you can define an implicit conversion to add a method like this to the Double class. This makes the following code very readable:

if (a ~= b) ...

Or, you can add the same method to a utilities object, if you prefer:

object MathUtils {
    def ~=(x: Double, y: Double, precision: Double) = {
        if ((x - y).abs < precision) true else false
    }
}

You can then invoke that method like a static method in Java:

println(MathUtils.~=(a, b, 0.000001))

With an implicit conversion, the name ~= is very readable, but in a utilities object like this that name doesn’t look right, so it might be better named approximatelyEqual, equalWithinTolerance, or some other name.

See Also

The Scala Cookbook

This tutorial is sponsored by the Scala Cookbook, which I wrote for O’Reilly:

You can find the Scala Cookbook here on Amazon.com.