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 += deviation2;
skew += deviation3;
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
Nicoló was 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