Scala除以零产生不同的结果
Posted
技术标签:
【中文标题】Scala除以零产生不同的结果【英文标题】:Scala division by zero yields different results 【发布时间】:2017-10-11 19:32:20 【问题描述】:我对 Scala 如何处理除以零感到困惑。这是一个 REPL 代码 sn-p。
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: / 零” “双数 = NaN” “双 = 无穷大”这使得调试非常具有挑战性,尤其是在处理未知特征的数据时。这种方法背后的原因是什么,甚至是一个更好的问题,如何在 Scala 中以统一的方式处理除零?
【问题讨论】:
我认为这与不同的数据类型有关。在执行不同但相关的计算时,请尝试始终使用相同的数据类型。例如:Double、Int 等 您可能正在处理未知特征的数据,但在像 Scala 这样的静态类型语言中,您处理的不是未知类型的数据。 @AlexeyRomanov 我明白你的意思。但是,我想大多数人都会同意这种方法容易出现一些非常肮脏的错误,并且在您编写的每一个算术运算中都非常繁琐。 【参考方案1】:这一切都归结为各种类型的除零规则。
0 / 0
是一个 被零除的整数(因为两个参数都是整数文字),这是抛出 java.lang.ArithmeticException
所必需的。
1.toDouble/0.toDouble
是一个 浮点除以零,分子为正数,计算结果为 +Infinity
所必需的。
0.0/0.0
是用零分子除以零的浮点数,它需要计算为+NaN
。
第一个是 Java 和 Scala 的约定,另外两个是 IEEE754 浮点的属性,这是 Java 和 Scala 都使用的。
【讨论】:
【参考方案2】:Doubles
和 Floats
是 floating-point
值 (more here),可以表示为 +Infinity
-Infinity
和 NaN
,如 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
来返回“无结果”而不显示异常
Try(x/y).toOption
【讨论】:
谢谢。您的回答非常有帮助,因为它详细说明了可能的解决方案。 我发现Try(1.0 / 0.0)
将返回 Success(Infinity)
而不是 Failure
并且 OrElse
不会返回。【参考方案3】:
您可以将部分函数用于这样的事情。例如:
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除以零产生不同的结果的主要内容,如果未能解决你的问题,请参考以下文章