scala3 icon indicating copy to clipboard operation
scala3 copied to clipboard

Performance concern regarding NumericRange.contains

Open klaeufer opened this issue 6 months ago • 3 comments

Compiler version

3.7.0 and probably all prior

Minimized example

val m = Integer.MAX_VALUE.toLong
val n = 1000000000
val i = 2L * m - 2L
val range = m until i + 1L

val t0 = System.currentTimeMillis ; (1 to n) foreach (_ => range.start <= i && i < range.end) ; System.currentTimeMillis - t0

val t1 = System.currentTimeMillis ; (1 to n) foreach (_ => range.contains(i)) ; System.currentTimeMillis - t1

Output

val i: Long = 4294967292
val m: Int = 2147483647
val n: Int = 1000000000
val range: scala.collection.immutable.NumericRange.Exclusive[Long] = NumericRange 2147483647 until 4294967293

val t0: Long = 1748538438604
val res1: Long = 5533

val t1: Long = 1748538462486
val res3: Long = 14021

Expectation

res3 should be similar to res1, not two to three times as much.

klaeufer avatar May 29 '25 17:05 klaeufer

refs: https://github.com/scala/scala3/discussions/18044

He-Pin avatar May 29 '25 17:05 He-Pin

Range is an Int range. IMO there is no more reason to specialize its contains method for Longs than for Doubles or BigInts.

May I suggest to alter the call site instead?

(1 to n) foreach (_ => i.toInt == i && range.contains(i.toInt))

sjrd avatar May 30 '25 14:05 sjrd

My bad for mentioning Range. That's not my use case, so I removed the link to Range.contains and updated the issue title.

val range: scala.collection.immutable.NumericRange.Exclusive[Long]

Here is the corresponding contains method:

https://github.com/scala/scala/blob/v2.13.16/src/library/scala/collection/immutable/NumericRange.scala#L290

Because of this inherent/essential additional cost, this might simply become an API documentation issue where we could recommend using an explicit comparison if performance is critical.

klaeufer avatar May 30 '25 19:05 klaeufer