Note that there are some explanatory texts on larger screens.

plurals
  1. POWhy is my Scala tail-recursion faster than the while loop?
    primarykey
    data
    text
    <p>Here are two solutions to exercise 4.9 in Cay Horstmann's Scala for the Impatient: "Write a function lteqgt(values: Array[Int], v: Int) that returns a triple containing the counts of values less than v, equal to v, and greater than v." One uses tail recursion, the other uses a while loop. I thought that both would compile to similar bytecode but the while loop is slower than the tail recursion by a factor of almost 2. This suggests to me that my while method is badly written.</p> <pre><code>import scala.annotation.tailrec import scala.util.Random object PerformanceTest { def main(args: Array[String]): Unit = { val bigArray:Array[Int] = fillArray(new Array[Int](100000000)) println(time(lteqgt(bigArray, 25))) println(time(lteqgt2(bigArray, 25))) } def time[T](block : =&gt; T):T = { val start = System.nanoTime : Double val result = block val end = System.nanoTime : Double println("Time = " + (end - start) / 1000000.0 + " millis") result } @tailrec def fillArray(a:Array[Int], pos:Int=0):Array[Int] = { if (pos == a.length) a else { a(pos) = Random.nextInt(50) fillArray(a, pos+1) } } @tailrec def lteqgt(values: Array[Int], v:Int, lt:Int=0, eq:Int=0, gt:Int=0, pos:Int=0):(Int, Int, Int) = { if (pos == values.length) (lt, eq, gt) else lteqgt(values, v, lt + (if (values(pos) &lt; v) 1 else 0), eq + (if (values(pos) == v) 1 else 0), gt + (if (values(pos) &gt; v) 1 else 0), pos+1) } def lteqgt2(values:Array[Int], v:Int):(Int, Int, Int) = { var lt = 0 var eq = 0 var gt = 0 var pos = 0 val limit = values.length while (pos &lt; limit) { if (values(pos) &gt; v) gt += 1 else if (values(pos) &lt; v) lt += 1 else eq += 1 pos += 1 } (lt, eq, gt) } } </code></pre> <p>Adjust the size of bigArray according to your heap size. Here is some sample output:</p> <pre><code>Time = 245.110899 millis (50004367,2003090,47992543) Time = 465.836894 millis (50004367,2003090,47992543) </code></pre> <p>Why is the while method so much slower than the tailrec? Naively the tailrec version looks to be at a slight disadvantage, as it must always perform 3 "if" checks for every iteration, whereas the while version will often only perform 1 or 2 tests due to the else construct. (NB reversing the order I perform the two methods does not affect the outcome).</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload