V P - 1 year ago 87
Scala Question

# Scala: How to check if a double value crossing Double limits?

I want to check if adding some value to a double value exceed the Double limits or not. I tried this:

`````` object Hello {
def main(args: Array[String]): Unit = {
var t = Double.MaxValue
var t2 = t+100000000
if(t2 > 0) {
println("t2 > 0: " + t2)
} else
println("t2 <= 0: " + t2)
}

}
``````

The output I get is

``````t2 > 0: 1.7976931348623157E308
``````

What I actually want is to sum billions of values and check whether or not the running sum overflows at any time.

The first part of your question seems to stem from a misunderstanding of floating-point numbers.

1. IEEE-754 floating-point numbers do not wrap around like some finite-size integers would. Instead, they "saturate" at `Double.PositiveInfinity`, which represents mathematical infinity. `Double.MaxValue` is the largest finite positive value of doubles. The next `Double` after that is `Double.PositiveInfinity`. Adding any double other than `Double.NegativeInfinity` and `NaN`s to `Double.PositiveInfinity` yields `Double.PositiveInfinity`.

``````scala> Double.PositiveInfinity + 1
res0: Double = Infinity

scala> Double.PositiveInfinity - 1
res1: Double = Infinity

scala> Double.PositiveInfinity + Double.NaN
res2: Double = NaN

scala> Double.PositiveInfinity + Double.NegativeInfinity
res3: Double = NaN
``````
2. Floating-point numbers get fewer and farther between as their magnitude grows. `Double.MaxValue + 100000000` evaluates to `Double.MaxValue` as a result of roundoff error: `Double.MaxValue` is so much larger than `100000000` that the former "swallows up" the latter if you try to add them. You would need to add a `Double` of the order of `math.pow(2, -52) * Double.MaxValue` to `Double.MaxValue` in order to get `Double.PositiveInfinity`:

``````scala> math.pow(2,-52) * Double.MaxValue + Double.MaxValue
res4: Double = Infinity
``````

Now, you write

What I actually want is to sum billions of values and check whether or not the running sum overflows at any time.

One possible approach is to define a function that adds the numbers recursively but stops if the running sum is an infinity or a `NaN`, and wraps the result in an `Either[String, Double]`:

``````import scala.collection.immutable

def sumToEither(xs: immutable.Seq[Double]): Either[String, Double] = {
@annotation.tailrec
def go(ys: immutable.Seq[Double], acc: Double): Double =
if (ys.isEmpty || acc.isInfinite || acc.isNaN) acc