Ruby Back to the Win32 Shootout
Back to dada's perl lab

[The Original Shootout]   [NEWS]   [FAQ]   [Methodology]   [Platform Details]   [Acknowledgements]   [Scorecard]  
All Source For ruby
Ackermann's Function
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: ackermann.ruby,v 1.6 2000/11/27 03:39:25 doug Exp $
# http://www.bagley.org/~doug/shootout/

def ack(m, n)
    if m == 0 then
    n + 1
    elsif n == 0 then
    ack(m - 1, 1)
    else
    ack(m - 1, ack(m, n - 1))
    end
end

NUM = Integer(ARGV.shift || 1)
print "Ack(3,", NUM, "): ", ack(3, NUM), "\n"

Array Access
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: ary3.ruby,v 1.1 2001/05/31 02:27:48 doug Exp $
# http://www.bagley.org/~doug/shootout/

n = Integer(ARGV.shift || 1)

i = 0
x = Array.new(n)
y = Array.new(n)
last = n-1

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

puts "#{y[0]} #{y[last]}"
Count Lines/Words/Chars
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: wc.ruby,v 1.5 2001/06/26 05:07:54 doug Exp $
# http://www.bagley.org/~doug/shootout/
# with help from Paul Brannan

nl = nw = nc = 0
loop do
  data = (STDIN.read(4096) or break) << (STDIN.gets || "")
  nc += data.length
  nl += data.count("\n")
  ((data.strip! || data).tr!("\n", " ") || data).squeeze!
  nw += data.count(" ") + 1
end
puts "#{nl} #{nw} #{nc}"
Echo Client/Server
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: echo.ruby,v 1.3 2001/05/08 08:08:41 doug Exp $
# http://www.bagley.org/~doug/shootout/

require "socket"

DATA = "Hello there sailor\n"

def echo_client(n, port)
    sock = TCPsocket.open('127.0.0.1', port)
    n.times do
    sock.write(DATA)
    ans = sock.readline
    if ans != DATA then
        raise sprintf("client: \"%s\" \"%s\"", DATA, ans)
    end
    end
    sock.close
end


def echo_server(n)
    ssock = TCPserver.open('127.0.0.1', 0)
    port = ssock.addr[1]
    if pid = fork then
    # parent is server
    csock = ssock.accept
    n = 0
    while str = csock.gets
        n += csock.write(str)
    end
    Process.wait
        printf "server processed %d bytes\n", n
    else
    # child is client
    echo_client(n, port)
    end
end

echo_server(Integer(ARGV.shift || 1))
Exception Mechanisms
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: except.ruby,v 1.3 2000/10/07 08:41:43 doug Exp $
# http://www.bagley.org/~doug/shootout/

$HI = 0
$LO = 0
NUM = Integer(ARGV[0] || 1)


class Lo_Exception < Exception
    def initialize(num)
        @value = num
        return self
    end
end

class Hi_Exception < Exception
    def initialize(num)
        @value = num
        return self
    end
end

def some_function(num)
    begin
    hi_function(num)
    rescue
        print "We shouldn't get here, exception is: #{$!.type}\n"
    end
end

def hi_function(num)
    begin
    lo_function(num)
    rescue Hi_Exception
    $HI = $HI + 1
    end
end

def lo_function(num)
    begin
    blowup(num)
    rescue Lo_Exception
    $LO = $LO + 1
    end
end

def blowup(num)
    if num % 2 == 0
    raise Lo_Exception.new(num)
    else
    raise Hi_Exception.new(num)
    end
end


for iter in 1 .. NUM
    some_function(iter)
end
print "Exceptions: HI=", $HI, " / LO=", $LO, "\n"
Fibonacci Numbers
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: fibo.ruby,v 1.2 2000/12/24 19:10:50 doug Exp $
# http://www.bagley.org/~doug/shootout/

def fib(n)
    if n < 2 then
    1
    else
    fib(n-2) + fib(n-1)
    end
end

N = Integer(ARGV.shift || 1)
puts fib(N)

Hash (Associative Array) Access
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: hash.ruby,v 1.2 2001/05/16 15:54:34 doug Exp $
# http://www.bagley.org/~doug/shootout/

n = Integer(ARGV.shift || 1)

X = {}
for i in 1 .. n
    X[sprintf("%x", i)] = 1
end

c = 0
(n).step(1,-1) do |i|
    if (X.has_key?(i.to_s)) then
    c += 1
    end
end

puts c
Hashes, Part II
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: hash2.ruby,v 1.2 2001/05/16 16:17:08 doug Exp $
# http://www.bagley.org/~doug/shootout/

n = Integer(ARGV.shift || 1)

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

printf "%d %d %d %d\n",
    hash1["foo_1"], hash1["foo_9999"], hash2["foo_1"], hash2["foo_9999"]
Heapsort
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: heapsort.ruby,v 1.7 2001/05/08 02:46:59 doug Exp $
# http://www.bagley.org/~doug/shootout/

IM = 139968
IA =   3877
IC =  29573

$last = 42.0
def gen_random (max) (max * ($last = ($last * IA + IC) % IM)) / IM end

def heapsort(n, ra)
    j = i = rra = 0
    l = (n >> 1) + 1
    ir = n

    while (1) do
    if (l > 1) then
        rra = ra[(l -= 1)]
    else
        rra = ra[ir]
        ra[ir] = ra[1]
        if ((ir -= 1) == 1) then
        ra[1] = rra
        return
        end
    end
    i = l
    j = l << 1
    while (j <= ir) do
        if ((j < ir) and (ra[j] < ra[j+1])) then
        j += 1
        end
        if (rra < ra[j]) then
        ra[i] = ra[j]
        j += (i = j)
        else
        j = ir + 1
        end
    end
    ra[i] = rra
    end
end

N = Integer(ARGV.shift || 1)
ary = []
for i in 1 .. N
    ary[i] = gen_random(1.0)
end

heapsort(N, ary)

printf "%.10f\n", ary[N]
Hello World
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: hello.ruby,v 1.1 2001/06/17 22:00:34 doug Exp $
# http://www.bagley.org/~doug/shootout/

puts "hello world"
List Operations
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: lists.ruby,v 1.5 2000/11/27 03:39:25 doug Exp $
# http://www.bagley.org/~doug/shootout/

NUM = Integer(ARGV.shift || 1)

SIZE = 10000

def test_lists()
    # create a list of integers (Li1) from 1 to SIZE
    li1 = (1..SIZE).to_a
    # copy the list to li2 (not by individual items)
    li2 = li1.dup
    # remove each individual item from left side of li2 and
    # append to right side of li3 (preserving order)
    li3 = Array.new
    while (not li2.empty?)
    li3.push(li2.shift)
    end
    # li2 must now be empty
    # remove each individual item from right side of li3 and
    # append to right side of li2 (reversing list)
    while (not li3.empty?)
    li2.push(li3.pop)
    end
    # li3 must now be empty
    # reverse li1 in place
    li1.reverse!
    # check that first item is now SIZE
    if li1[0] != SIZE then
    p "not SIZE"
    return(0)
    end
    # compare li1 and li2 for equality
    if li1 != li2 then
    return(0)
    end
    # return the length of the list
    return(li1.length)
end

for iter in 1 .. NUM
    result = test_lists()
end
print result, "\n"
Matrix Multiplication
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: matrix.ruby,v 1.3 2001/05/16 16:38:55 doug Exp $
# http://www.bagley.org/~doug/shootout/

n = Integer(ARGV.shift || 1)

size = 30

def mkmatrix(rows, cols)
    count = 1
    mx = Array.new(rows)
    for i in 0 .. (rows - 1)
    row = Array.new(cols, 0)
    for j in 0 .. (cols - 1)
        row[j] = count
        count += 1
    end
    mx[i] = row
    end
    mx
end

def mmult(rows, cols, m1, m2)
    m3 = Array.new(rows)
    for i in 0 .. (rows - 1)
    row = Array.new(cols, 0)
    for j in 0 .. (cols - 1)
        val = 0
        for k in 0 .. (cols - 1)
        val += m1[i][k] * m2[k][j]
        end
        row[j] = val
    end
    m3[i] = row
    end
    m3
end

m1 = mkmatrix(size, size)
m2 = mkmatrix(size, size)
mm = Array.new
n.times do
    mm = mmult(size, size, m1, m2)
end
puts "#{mm[0][0]} #{mm[2][3]} #{mm[3][2]} #{mm[4][4]}"
Method Calls
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: methcall.ruby,v 1.2 2000/12/24 22:04:51 doug Exp $
# http://www.bagley.org/~doug/shootout/

class Toggle
    def initialize(start_state)
    @bool = start_state
    self
    end
    def value()
    @bool
    end
    def activate()
    @bool = !@bool
    self
    end
end

class NthToggle < Toggle
    def initialize(start_state, max_counter)
    super(start_state)
    @count_max = max_counter
    @counter = 0
    self
    end
    def activate()
    @counter += 1
    if (@counter >= @count_max) then
        @bool = !@bool
        @counter = 0
    end
    self
    end
end

def main()
    n = Integer(ARGV.shift || 1)

    val = 1
    toggle = Toggle.new(val)
    n.times do
    val = toggle.activate().value()
    end
    if val then puts "true" else puts "false" end

    val = 1
    ntoggle = NthToggle.new(val, 3)
    n.times do
    val = ntoggle.activate().value()
    end
    if val then puts "true" else puts "false" end
end

main()

Nested Loops
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: nestedloop.ruby,v 1.2 2001/02/15 01:09:35 doug Exp $
# http://www.bagley.org/~doug/shootout/
# from Avi Bryant

n = Integer(ARGV.shift || 1)
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
puts x
Object Instantiation
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: objinst.ruby,v 1.2 2000/12/24 22:04:57 doug Exp $
# http://www.bagley.org/~doug/shootout/

class Toggle
    def initialize(start_state)
    @bool = start_state
    self
    end
    def value()
    @bool
    end
    def activate()
    @bool = !@bool
    self
    end
end

class NthToggle < Toggle
    def initialize(start_state, max_counter)
    super(start_state)
    @count_max = max_counter
    @counter = 0
    self
    end
    def activate()
    @counter += 1
    if (@counter >= @count_max) then
        @bool = !@bool
        @counter = 0
    end
    self
    end
end

def main()
    n = Integer(ARGV.shift || 1)

    toggle = Toggle.new(1)
    5.times do
    if toggle.activate().value() then puts "true" else puts "false" end
    end
    n.times do
    toggle = Toggle.new(1)
    end

    puts

    ntoggle = NthToggle.new(1, 3)
    8.times do
    if ntoggle.activate().value() then puts "true" else puts "false" end
    end
    n.times do
    ntoggle = NthToggle.new(1, 3)
    end
end

main()

Producer/Consumer Threads
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: prodcons.ruby,v 1.2 2000/12/20 04:33:20 doug Exp $
# http://www.bagley.org/~doug/shootout/

require 'thread'

def main(n)
    mutex = Mutex.new
    access = ConditionVariable.new
    count = data = consumed = produced = 0
    consumer = Thread.new do
    i = 0
    loop do
        mutex.synchronize {
        while count == 0 do access.wait(mutex) end
        i = data
        count = 0
        access.signal
        }
        consumed += 1
        if i == n then break end
    end
    end
    producer = Thread.new do
    for i in 1 .. n do
        mutex.synchronize {
        while count == 1 do access.wait(mutex) end
        data = i
        count = 1
        access.signal
        }
        produced += 1
    end
    end
    producer.join
    consumer.join
    puts "#{produced} #{consumed}"
end

main(Integer(ARGV.shift || 1))
Random Number Generator
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: random.ruby,v 1.13 2001/05/08 06:35:57 doug Exp $
# http://www.bagley.org/~doug/shootout/

IM = 139968
IA = 3877
IC = 29573

$last = 42.0
def gen_random (max) (max * ($last = ($last * IA + IC) % IM)) / IM end

N = Integer(ARGV.shift || 1)
result = 0
N.times do
    result = gen_random(100.0)
end
printf "%.9f\n", result
Regular Expression Matching
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: regexmatch.ruby,v 1.11 2001/07/02 04:26:31 doug Exp $
# http://www.bagley.org/~doug/shootout/

re = Regexp.new(
    '(?:^|[^\d\(])' +            # must be preceeded by non-digit
    '(?:\((\d\d\d)\)|(\d\d\d))' +    # match 1 or 2: area code is 3 digits
    '[ ]' +                # area code followed by one space
    '(\d\d\d)' +            # match 3: prefix of 3 digits
    '[ -]' +                # separator is either space or dash
    '(\d\d\d\d)' +            # match 4: last 4 digits
    '\D'                # must be followed by a non-digit
)

NUM = Integer(ARGV[0] || 1)

phones = STDIN.readlines

count = m = line = iter = 0
for iter in 1..NUM
    for line in phones
    if m = re.match(line)
        m1 = m[1];
        if m1 == "" 
            m1 = m[2];
        end
        num = '(' + m1 + ') ' + m[3] + '-' + m[4];
        if iter == NUM
        count += 1
        puts "#{count}: #{num}"
        end
    end
    end
end
Reverse a File
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: reversefile.ruby,v 1.2 2000/11/27 03:39:26 doug Exp $
# http://www.bagley.org/~doug/shootout/

print STDIN.readlines().reverse()

Sieve of Erathostenes
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: sieve.ruby,v 1.12 2001/05/06 04:37:45 doug Exp $
# http://www.bagley.org/~doug/shootout/

NUM = Integer(ARGV.shift || 1)

count = i = j = 0
flags0 = Array.new(8192,1)

NUM.times do
    count = 0
    flags = flags0.dup
    for i in 2 .. 8192
    next unless flags[i]
    # remove all multiples of prime: i
    (i*i).step(8192, i) do |j|
        flags[j] = nil
    end
    count = count + 1
    end
end

print "Count: ", count, "\n"

Spell Checker
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: spellcheck.ruby,v 1.6 2001/01/23 01:30:42 doug Exp $
# http://www.bagley.org/~doug/shootout/

dict = Hash.new
file = open("Usr.Dict.Words")
while file.gets()
    dict[$_.chomp!] = 1
end
file.close()

count = word = 0
while STDIN.gets()
    unless dict.has_key? $_.chomp!
    puts $_
    end
end
Statistical Moments
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: moments.ruby,v 1.5 2001/01/05 01:35:56 doug Exp $
# http://www.bagley.org/~doug/shootout/

# throw away unused parameter sent by benchmark framework
ARGV.shift()

sum = 0.0
nums = []
num = nil
deviation = nil

STDIN.readlines().each{|line|
    num = Float(line)
    nums << num
    sum += num
}
n = nums.length()
mean = sum/n;
average_deviation = 0
standard_deviation = 0
variance = 0
skew = 0
kurtosis = 0

nums.each{|num|
    deviation = num - mean
    average_deviation += deviation.abs()
    variance += deviation**2;
    skew += deviation**3;
    kurtosis += deviation**4
}
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[mid] + nums[mid-1])/2
else
    median = nums[mid]
end

printf("n:                  %d\n", n)
printf("median:             %f\n", median)
printf("mean:               %f\n", mean)
printf("average_deviation:  %f\n", average_deviation)
printf("standard_deviation: %f\n", standard_deviation)
printf("variance:           %f\n", variance)
printf("skew:               %f\n", skew)
printf("kurtosis:           %f\n", kurtosis)
String Concatenation
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: strcat.ruby,v 1.2 2000/12/23 15:52:44 doug Exp $
# http://www.bagley.org/~doug/shootout/

# Benedikt Rosenau suggested using
#   str << "hello\n"
# which is orders of magnitude faster than:
#   str += "hello\n"

n = Integer(ARGV.shift || 1)

str = ''
for i in 1 .. n
    str << "hello\n"
end
puts str.length
Sum a Column of Integers
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: sumcol.ruby,v 1.4 2001/01/04 20:09:24 doug Exp $
# http://www.bagley.org/~doug/shootout/
# from: Mathieu Bouchard

count = 0
while STDIN.gets()
    count += $_.to_i
end
puts count
Word Frequency Count
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: wordfreq.ruby,v 1.9 2001/05/16 23:46:40 doug Exp $
# http://www.bagley.org/~doug/shootout/

freq = Hash.new(0)
loop {
    data = (STDIN.read(4095) or break) << (STDIN.gets || "")
    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) }
print lines.sort.reverse