如何在Double上执行算术时覆盖NaN或Infinity结果?

时间:2014-07-27 13:12:41

标签: scala floating-point division

我正在对一组数字和一些结果进行计算 这些计算返回NaNInfinity的结果 调查后我发现根本原因是因为 以下算术分工:

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
}

我认为在这些情况下回答为什么NaNInfinity更多的是 数学问题,但有趣的是0/0抛出ArithmeticException 虽然0.0/0.0没有?

我使用这些计算结果执行降序排序:NaN& Infinity 当我要求它们最后出现时,会导致元素首先出现。

如何确保返回NaNInfinity的任何计算 它排序后出现在最后?我可以在结果中查看NaNInfinity吗? 计算,如果它满足只分配给0.0

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

1 个答案:

答案 0 :(得分:2)

使用NaN而不是例外的原因实际上是一个更普遍的问题,this answer中对此进行了解释。

目前还不清楚你是如何进行排序的,但默认情况下,正无穷大的排序顺序正确,NaN排在最后(按升序排列):

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)

修改行为的任何简单方法都是在排序之前映射和匹配列表。

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
}

按升序排列,Double.NegativeInfinity首先出现,然后是所有升序实数,然后Double.PositiveInfinity后跟NaN。如果您希望 PositiveInfinityNegativeInfinity以及NaN按降序排在最后,那么您可以将它们全部映射到Double.NegativeInfinity