nietaki
nietaki

Reputation: 9018

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

This is a piece of code to generate random Long values within a given range, simplified for clarity:

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
}

I know the results of this aren't uniform and this wouldn't work correctly for some values of min and max, but that's beside the point.

In the tests it turned out, that the following assertion isn't always true:

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

More specifically the returned value is -3. How is that even possible?

Upvotes: 2

Views: 181

Answers (1)

nietaki
nietaki

Reputation: 9018

As it turns out, math.abs(x: Long): Long isn't guaranteed to always return non-negative values! There is no Long value that could represent math.abs(Long.MinValue), so instead of throwing an exception, 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

Which is, in my opinion, a very good example of why one should be using ScalaCheck to test at least parts of their codebase.

Upvotes: 3

Related Questions