I wrote a Groovy version of the same Ruby code I had used to benchmark JRuby. This was an extremely straightforward port. I was amazed at just how similar Groovy's syntax is to Ruby. Here is the code:

def expo(n,p){

def r = n % p

def exp = 0

def div = p

while (r == 0){

exp += 1

div *= p

r = n % div

}

return exp

}

def factor(n){

def factors = new java.util.HashMap<Integer,Integer>()

def s = n * 0.5

def p = (2..s).toArray()

p.each{

if (it) {

def r = expo(n,it)

if (r){

factors[it] = r

}

def val = it*2

while (val <= s){

p[val -2] = null

val += it

}

}

}

return factors

}

def numDivisors(n){

def total = 1

factor(n).values().each{

total *= (it+1)

}

return total

}

def n = 2

def num = 1

def max = Integer.parseInt(this.args[0])

def Integer triangle = 0

while (num <= max){

triangle = n*(n+1) * 0.5

num = numDivisors(triangle)

n += 1

}

println(triangle)

Anyways, here is the chart.

There is definitely a performance boost for long running processes where JIT'ing can happen more easily in 1.6. It was not as dramatic as I thought it might be, but it is there. Of course this is just one silly benchmark that is heavy in integer math, so take that for what it's worth.

I also compared Groovy and JRuby. This was also surprising:

Pretty close! Groovy seems to start-up a little slower, but pulled ahead slightly on bigger tasks. Perhaps the apprentice has overtaken the master.

Also, just for kicks, I tried out Scala. Here is the code:

import scala.collection.mutable._

object Euler12{

def expo(n:int, p:int):int = {

var r = n % p

var exp = 0

var div = p

while (r == 0){

exp = exp + 1

r = n % div

div = div * p

}

if (exp == 0 ) 0 else (exp-1)

}

def factor(n:int):Map[int,int] = {

var factors = new HashMap[int,int]()

var s:int = (n/2) + 1

val p = (2 until s).toArray

p.foreach( (num) => {

if (num > 1){

val r = expo(n, num)

if (r > 0){

factors.put(num, r)

}

var i = num*2

while ((i-2) < p.length){

p(i - 2) = 0

i = i + num

}

}

})

return factors

}

def numDivisors(n:int):int = {

var total = 1

factor(n).values.foreach((num) => {

total = total * (num+1)

})

factor(n).values.foldLeft(1)((p,m) => {

p * (m+1)

})

}

def main(args:Array[String]) : Unit = {

val t = new java.util.Date()

var n = 1

var num = 1

val max = Integer.parseInt(args(0))

var triangle = 3

while (num <= max){

triangle = n*(n+1)/2

num = numDivisors(triangle)

n = n + 1

}

println(triangle)

}

}

This turned out to not be fair. Scala's performance is exactly on par with Java and thus blows away JRuby and Groovy.

I guess that is what happens when you have a language written by a guy who once wrote javac... Actually I would guess this is mostly a function of the static typing in Scala. It certainly bodes well for initiatives to bring features of Scala, like (BGGA-style) closures and type inference, to Java. It seems possible to implement all of this with no impact on performance, even on a JVM that has not been made to support such features.

## No comments:

Post a Comment