为什么 scala return 在此模运算中超出范围值?

Why does scala return an out of range value in this modulo operation?

这是一段在给定范围内生成随机 Long 值的代码,为清楚起见进行了简化:

def getLong(min: Long, max: Long): Long = {
  if(min > max) {
    throw new IncorrectBoundsException
  }
  val rangeSize = (max - min + 1L)
  val randValue = math.abs(Random.nextLong())
  val result = (randValue % (rangeSize)) + min
  result
}

我知道这不是统一的结果,对于 minmax 的某些值,这将无法正常工作,但这不是重点。

在测试中证明,以下断言并不总是正确的:

getLong(-1L, 1L) >= -1L

更具体地说,返回值为 -3。这怎么可能?

事实证明,math.abs(x: Long): Long 不能保证总是 return 非负值!没有可以表示 math.abs(Long.MinValue)Long 值,因此不会抛出异常,而是 math.abs returns Long.MinValue:

scala> Long.MinValue
res27: Long = -9223372036854775808

scala> math.abs(Long.MinValue)
res28: Long = -9223372036854775808

scala> math.abs(Long.MinValue) % 3
res29: Long = -2

scala> math.abs(Long.MinValue) % 3 + (-1)
res30: Long = -3

在我看来,这是一个很好的例子,说明为什么应该使用 ScalaCheck 来测试至少部分代码库。