Hi all,

One of the concerns I'm having about Ruby 1.8 is that it appears to be
getting *slower*.  Not so much that it will be a serious issue for me,
but Ruby's speed has been something some of the Perl and Python folks
have been using against Ruby.  I visited the Great Computer Language
Shootout (http://www.bagley.org/~doug/shootout/), put together 9 of
the functions he used and ran them using both 1.6.8 and 1.8 p2.

In 7 of the 9 tests, 1.8 was *slower*.  Should I be worried?

Here is a sampling of the results.  Complete code at the bottom.  I
ran the benchmarks and almost always came up with the same results -
1.6.8 was faster in 7 of 9 tests (and sometimes 8).  The one place
where I noticed a massive improvement, however, was in the 'list'
test.

Dual Pentium II 400
512 MB RAM
Mandrake Linux 9.0

# 1.6.8
                       user     system      total        real
Ackermann function:    1.430000   0.000000   1.430000 (  1.450032)
Array access:          9.010000   0.020000   9.030000 (  9.139022)
Fibonacci numbers:     8.940000   0.010000   8.950000 (  9.036173)
Hash access I:         7.260000   0.000000   7.260000 (  7.241685)
Hash access II:        9.960000   0.060000  10.020000 ( 10.047116)
Lists:                 19.250000  0.050000  19.300000 ( 19.398597)
Nested loop:           10.460000 0.010000  10.470000 ( 10.538426)
Sieve of Eratosthenes: 13.880000   0.040000  13.920000 ( 13.926563)
Word Frequency:        2.700000   0.000000   2.700000 (  2.669599)

# 1.8.0 preview 2
                       user     system      total        real
Ackermann function:    1.560000   0.000000   1.560000 (  1.545286)
Array access:          10.020000   0.010000  10.030000 ( 10.017142)
Fibonacci numbers:     9.130000   0.010000   9.140000 (  9.201564)
Hash access I:         7.960000   0.010000   7.970000 (  8.046752)
Hash access II:        9.780000   0.030000   9.810000 (  9.939460)
Lists:                 2.320000   0.020000   2.340000 (  2.337373)
Nested loop:           11.850000   0.000000  11.850000 ( 11.849551)
Sieve of Eratosthenes: 15.030000   0.040000  15.070000 ( 15.065020)
Word Frequency:        2.990000   0.020000   3.010000 (  3.003743)

# benchmark.rb
require "gcls"
require "benchmark"
include Benchmark

max = 300000
bm do |x|
   x.report("Ackermann function: "){
      max.times{ ack }
   }
   x.report("Array access: "){
      1000.times{ array_access }
   }
   x.report("Fibonacci numbers: "){
      100.times{ fib }
   }
   x.report("Hash access I: "){
      10000.times{ hash_access_I }
   }
   x.report("Hash access II: "){
      5.times{ hash_access_II }
   }
   x.report("Lists: "){
      3.times{
         for iter in 1..10
            result = lists
         end
      }
   }
   x.report("Nested loop: "){
      5.times{ nested_loop }
   }
   x.report("Sieve of Eratosthenes: "){
      10.times{ sieve_of_eratosthenes }
   }
   x.report("Word Frequency: "){
      1000.times{ word_frequency }
   }
end

# gcls.rb
# Ackermann function
def ack(m=0, n=0)
   if m == 0 then
	   n + 1
   elsif n == 0 then
	   ack(m - 1, 1)
   else
	   ack(m - 1, ack(m, n - 1))
   end
end

# Array access
def array_access(n=1)
   x = Array.new(n)
   y = Array.new(n, 0)

   for i in 0...n
      x[i] = i + 1
   end

   for k in 0..999
      (n-1).step(0,-1) do |i|
         y[i] = y.at(i) + x.at(i)
      end
   end
end

# Fibonacci numbers
def fib(n=20)
   if n < 2 then
   	1
   else
   	fib(n-2) + fib(n-1)
   end
end
   
# Hash Access I
def hash_access_I(n=20)
   hash = {}
   for i in 1..n
      hash['%x' % i] = 1
   end

   c = 0
   n.downto 1 do |i|
      c += 1 if hash.has_key? i.to_s
   end
end

# Hash Access II
def hash_access_II(n=20)
   hash1 = {}
   for i in 0 .. 9999
      hash1["foo_" << i.to_s] = i
   end

   hash2 = Hash.new(0)
   n.times do
      for k in hash1.keys
         hash2[k] += hash1[k]
      end
   end
end   

# lists
SIZE = 10000
def lists
   li1 = (1..SIZE).to_a
   li2 = li1.dup
   li3 = Array.new

   while (not li2.empty?)
      li3.push(li2.shift)
   end

   while (not li3.empty?)
      li2.push(li3.pop)
   end

   li1.reverse!

   if li1[0] != SIZE then
      p "not SIZE"
	   return(0)
   end

   if li1 != li2 then
	   return(0)
   end

   return(li1.length)
end

def nested_loop(n = 10)
   x = 0
   n.times do
      n.times do
         n.times do
            n.times do
               n.times do
                  n.times do
			            x += 1
                  end
               end
            end
         end
      end
   end
end

def sieve_of_eratosthenes(n=20)
   count = i = j = 0
   flags0 = Array.new(8192,1)

   n.times do
      count = 0
      flags = flags0.dup
      for i in 2 .. 8192
         next unless flags[i]
	      (i+i).step(8192, i) do |j|
	         flags[j] = nil
	      end
         count = count + 1
      end
   end
end

def statistical_moments
   sum = 0.0
   nums = []
   num = nil

   for line in STDIN.readlines()
	   num = Float(line)
	   nums << num
	   sum += num
   end

   n = nums.length()
   mean = sum/n;
   deviation = 0.0
   average_deviation = 0.0
   standard_deviation = 0.0
   variance = 0.0
   skew = 0.0
   kurtosis = 0.0
    
   for num in nums
	   deviation = num - mean
	   average_deviation += deviation.abs()
	   variance += deviation**2;
	   skew += deviation**3;
	   kurtosis += deviation**4
   end

   average_deviation /= n
   variance /= (n - 1)
   standard_deviation = Math.sqrt(variance)

   if (variance > 0.0)
	   skew /= (n * variance * standard_deviation)
	   kurtosis = kurtosis/(n * variance * variance) - 3.0
   end

   nums.sort()
   mid = n / 2
    
   if (n % 2) == 0
	   median = (nums.at(mid) + nums.at(mid-1))/2
   else
	   median = nums.at(mid)
   end
end

def word_frequency
   data = "While the word Machiavellian suggests cunning, duplicity,
or bad faith, it would be unfair to equate the word with the man. Old
Nicolwas actually a devout and principled man, who had profound
insight into human nature and the politics of his time. Far more
worthy of the pejorative implication is Cesare Borgia, the incestuous
and multi-homicidal pope who was the inspiration for The Prince. You
too may ponder the question that preoccupied Machiavelli: can a
government stay in power if it practices the morality that it preaches
to its people?"
   freq = Hash.new(0)
   for word in data.downcase.tr_s('^A-Za-z',' ').split(' ')
      freq[word] += 1
   end
   freq.delete("")
   lines = Array.new
   freq.each{|w,c| lines << sprintf("%7d\t%s\n", c, w) }
end

Regards,

Dan