blue-sky
blue-sky

Reputation: 53806

How to overwrite NaN or Infinity result when performing arithmetic on Double?

I'm running a calculation on a group of numbers and some of the results of those calculations returns result of NaN or Infinity After investigating I discovered that the root cause is because of below arithmetic division :

object doublefun {
  println("Welcome to the Scala worksheet")       //> Welcome to the Scala worksheet

  val d1 = 0.0                                    //> d1  : Double = 0.0
  val d2 = 0.0                                    //> d2  : Double = 0.0

  val d = d1/d2                                   //> d  : Double = NaN

  val i1 = 1.0                                    //> i1  : Double = 1.0
  val i2 = 0.0                                    //> i2  : Double = 0.0

  val i = i1/i2                                   //> i  : Double = Infinity

  val o1 = 0                                      //> o1  : Int = 0
  val o2 = 0                                      //> o2  : Int = 0
  val o = o1/o2                                   //> java.lang.ArithmeticException: / by zero
}

I think asking why NaN and Infinity are returned in these cases is more of a math question but it is interesting that 0/0 throws an ArithmeticException while 0.0/0.0 does not ?

I'm using the result of these calculation to perform a sort descending : NaN & Infinity results in elements appearing first when I require them to appear last.

How can I ensure that for any calculation which returns NaN or Infinity that it appears last when sorted ? Can I check for NaN or Infinity within the result of the calculation and if it satisfies just assign to 0.0 :

if(d == Double.Infinity || d == Double.NaN){
  return 0.0
}

Upvotes: 1

Views: 2654

Answers (1)

Michael Zajac
Michael Zajac

Reputation: 55569

The reason behind the use of NaN and not an exception is really a more general question, which is explained in this answer.

It's unclear how you're doing your sorting, but by default positive and negative infinity are in the correct sort order, and NaN comes last (in ascending order):

scala> List(Double.PositiveInfinity, Double.NegativeInfinity, Double.NaN, 0.0, -1.0, 2.0).sorted
res15: List[Double] = List(-Infinity, -1.0, 0.0, 2.0, Infinity, NaN)

Any easy way to modify the behavior would be to map and match a list before sorting.

val list = List(Double.PositiveInfinity, Double.NegativeInfinity, Double.NaN, 0.0, -1.0, 2.0)

list.map {
    case d if(d.isNaN) => 0.0 // Or whatever value you'd prefer.
    case d if(d.isNegInfinity) => 0.0 // Or whatever value you'd prefer.
    case d if(d.isPosInfinity) => 0.0 // Or whatever value you'd prefer.
    case d => d
}

In ascending order, Double.NegativeInfinity comes first, then all of the ascending real numbers, then Double.PositiveInfinity followed by NaN. If you want both PositiveInfinity and NegativeInfinity as well as NaN to come last in descending order, then you could map them all to Double.NegativeInfinity.

Upvotes: 2

Related Questions