IOD*_*DEV 9 scala integer-overflow biginteger
从应用程序开发团队的角度来看,处理整数溢出(如999999*999999(结果> Integer.MAX_VALUE))的常见做法是什么?
人们可以BigInt
强制要求并禁止使用Integer
,但这是一个好/坏的想法?
Rex*_*err 13
如果整数不溢出非常重要,您可以定义自己的溢出操作,例如:
def +?+(i: Int, j: Int) = {
val ans = i.toLong + j.toLong
if (ans < Int.MinValue || ans > Int.MaxValue) {
throw new ArithmeticException("Int out of bounds")
}
ans.toInt
}
Run Code Online (Sandbox Code Playgroud)
您可以使用enrich-your-library模式将其转换为运算符; 如果JVM设法正确地进行逃逸分析,你将不会受到太多的惩罚:
class SafePlusInt(i: Int) {
def +?+(j: Int) = { /* as before, except without i param */ }
}
implicit def int_can_be_safe(i: Int) = new SafePlusInt(i)
Run Code Online (Sandbox Code Playgroud)
例如:
scala> 1000000000 +?+ 1000000000
res0: Int = 2000000000
scala> 2000000000 +?+ 2000000000
java.lang.ArithmeticException: Int out of bounds
at SafePlusInt.$plus$qmark$plus(<console>:12)
...
Run Code Online (Sandbox Code Playgroud)
如果它不是非常重要,那么标准单元测试和代码审查等应该在大多数情况下都能解决问题.使用BigInt
是可能的,但会减慢你的算术速度100倍左右,当你必须使用现有的方法时,它将无法帮助你Int
.
如果您正在使用Scala(并且基于我假设您的标记),一个非常通用的解决方案是针对scala.math.Integral
类型类编写库代码:
def naturals[A](implicit f: Integral[A]) =
Stream.iterate(f.one)(f.plus(_, f.one))
Run Code Online (Sandbox Code Playgroud)
您还可以使用上下文边界和Integral.Implicits
更好的语法:
import scala.math.Integral.Implicits._
def squares[A: Integral] = naturals.map(n => n * n)
Run Code Online (Sandbox Code Playgroud)
现在,您可以使用这些方法无论用Int
或Long
或BigInt
根据需要,因为实例Integral
为所有这些存在:
scala> squares[Int].take(10).toList
res0: List[Int] = List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
scala> squares[Long].take(10).toList
res0: List[Long] = List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
scala> squares[BigInt].take(10).toList
res1: List[BigInt] = List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
Run Code Online (Sandbox Code Playgroud)
无需更改库代码:只需使用Long
或BigInt
溢出是一个问题,Int
否则.
您将支付在性能方面的一些损失,但通用性和推迟的能力Int
-或者BigInt
决定可能是值得的.
到目前为止,关于整数溢出的最常见做法是程序员应该知道问题存在,要注意它们可能发生的情况,并进行适当的检查或重新排列数学,以便不会发生溢出,例如做*(b/c)而不是(a*b)/ c.如果项目使用单元测试,它们将包括尝试强制溢出的情况.
我从来没有工作或看过一个需要更多的团队的代码,所以我会说这对几乎所有的软件来说都足够好了.
我见过的一个嵌入式应用程序,实际上,诚实的意大利面 - 怪物需要防止溢出,他们通过证明溢出不可能在每一行看起来可能发生溢出.