V P - 1 year ago 69

Scala Question

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.

Recommended for you: Get network issues from **WhatsUp Gold**. **Not end users.**

Answer Source

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

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`

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
else go(ys.tail, ys.head + acc)
go(xs, 0.0) match {
case x if x.isInfinite => Left("overflow")
case x if x.isNaN => Left("NaN")
case x => Right(x)
}
}
```