Scala 除以零会产生不同的结果
Scala division by zero yields different results
我对 Scala 如何处理被零除感到困惑。这是一个 REPL 代码片段。
scala> 1/0
java.lang.ArithmeticException: / by zero
... 33 elided
scala> 1.toDouble/0.toDouble
res1: Double = Infinity
scala> 0.0/0.0
res2: Double = NaN
scala> 0/0
java.lang.ArithmeticException: / by zero
... 33 elided
scala> 1.toInt/0.toInt
java.lang.ArithmeticException: / by zero
... 33 elided
如您在上面的示例中所见,根据除以零的方式,您会得到以下结果之一:
- "java.lang.ArithmeticException: / by zero"
- "Double = NaN"
- "Double = Infinity"
这使得调试非常具有挑战性,尤其是在处理未知特征的数据时。这种方法背后的原因是什么,或者更好的问题是,如何在 Scala 中以统一的方式处理被零除?
这一切都归结为各种类型的除零规则。
0 / 0
是 整数除以零 (因为两个参数都是整数文字),并且需要抛出 java.lang.ArithmeticException
.
1.toDouble/0.toDouble
是 浮点数除以零 且分子为正数,需要计算为 +Infinity
.
0.0/0.0
是一个分子为零的浮点数除法,计算结果为 +NaN
.
是必需的
第一个是 Java 和 Scala 约定,另外两个是 IEEE754 浮点的属性,Java 和 Scala 都使用。
Doubles
和 Floats
是 floating-point
值(more here) which can be represented as +Infinity
-Infinity
and NaN
as defined in IEEE 754 标准。
Integers
是 fixed numbers
,它们无法明确指示无效数据,因此它们会抛出 exceptions
对此的统一解决方案是在 Try
上使用 getOrElse
方法
Try(x/y).getOrElse(0)
如果您只想在 ArithmeticException
上恢复,您可以使用 recover
和 get
Try(x/y).recover{ case _: ArithmeticException => 0 }.get
recover
允许您将 Failure
转换为 Success
您也可以使用 Try
到 Option
到 return "no result" 而不显示异常
Try(x/y).toOption
你可以使用偏函数来做这样的事情。例如:
object MyObject {
def main(args: Array[String]) {
println(safeDiv.isDefinedAt(1.0, 1.0)) // true
println(safeDiv.isDefinedAt(1.0, 0.0)) // false
println(safeDiv(1.0, 1.0)) // 1.0
println(safeDiv(1.0, 0.0)) // crash
}
def safeDiv: PartialFunction[(Double, Double), Double] = {
case(a,b) if b != 0.0 => a/b
}
}
部分函数允许您检查是否为给定输入定义了函数。在上面的示例中,我说如果除数为 0.0,则函数 safeDiv
未定义。因此,您可以检查函数是否会在给定输入的情况下执行。不需要检查,但是 safeDiv(1.0, 0.0)
不会执行。
偏函数是你反对这样的东西的朋友:
scala> (1.0/0.0).toInt
res22: Int = 2147483647
我对 Scala 如何处理被零除感到困惑。这是一个 REPL 代码片段。
scala> 1/0
java.lang.ArithmeticException: / by zero
... 33 elided
scala> 1.toDouble/0.toDouble
res1: Double = Infinity
scala> 0.0/0.0
res2: Double = NaN
scala> 0/0
java.lang.ArithmeticException: / by zero
... 33 elided
scala> 1.toInt/0.toInt
java.lang.ArithmeticException: / by zero
... 33 elided
如您在上面的示例中所见,根据除以零的方式,您会得到以下结果之一:
- "java.lang.ArithmeticException: / by zero"
- "Double = NaN"
- "Double = Infinity"
这使得调试非常具有挑战性,尤其是在处理未知特征的数据时。这种方法背后的原因是什么,或者更好的问题是,如何在 Scala 中以统一的方式处理被零除?
这一切都归结为各种类型的除零规则。
0 / 0
是 整数除以零 (因为两个参数都是整数文字),并且需要抛出 java.lang.ArithmeticException
.
1.toDouble/0.toDouble
是 浮点数除以零 且分子为正数,需要计算为 +Infinity
.
0.0/0.0
是一个分子为零的浮点数除法,计算结果为 +NaN
.
第一个是 Java 和 Scala 约定,另外两个是 IEEE754 浮点的属性,Java 和 Scala 都使用。
Doubles
和 Floats
是 floating-point
值(more here) which can be represented as +Infinity
-Infinity
and NaN
as defined in IEEE 754 标准。
Integers
是 fixed numbers
,它们无法明确指示无效数据,因此它们会抛出 exceptions
对此的统一解决方案是在 Try
getOrElse
方法
Try(x/y).getOrElse(0)
如果您只想在 ArithmeticException
上恢复,您可以使用 recover
和 get
Try(x/y).recover{ case _: ArithmeticException => 0 }.get
recover
允许您将 Failure
转换为 Success
您也可以使用 Try
到 Option
到 return "no result" 而不显示异常
Try(x/y).toOption
你可以使用偏函数来做这样的事情。例如:
object MyObject {
def main(args: Array[String]) {
println(safeDiv.isDefinedAt(1.0, 1.0)) // true
println(safeDiv.isDefinedAt(1.0, 0.0)) // false
println(safeDiv(1.0, 1.0)) // 1.0
println(safeDiv(1.0, 0.0)) // crash
}
def safeDiv: PartialFunction[(Double, Double), Double] = {
case(a,b) if b != 0.0 => a/b
}
}
部分函数允许您检查是否为给定输入定义了函数。在上面的示例中,我说如果除数为 0.0,则函数 safeDiv
未定义。因此,您可以检查函数是否会在给定输入的情况下执行。不需要检查,但是 safeDiv(1.0, 0.0)
不会执行。
偏函数是你反对这样的东西的朋友:
scala> (1.0/0.0).toInt
res22: Int = 2147483647