I saw the beauty of Ruby Re: 1. Ruby result: 101 seconds , 2. Java result:9.8 seconds, 3. Perl result:62 seconds

Thank you for everyone who replied my first post with my first Ruby program here directly or indirectly. It is really a great community, a lot of fun. I did not expect I could learn so much. Here are some of I learned from everyone: 1) everything is object,so all are method calls (to_i, to_f, each, ...) . 2)open class even for Integer, String... ,.3) method chain , 4) .yield and code block and more. And especially I have to thank the following people:

Florian Frank : not , enum, .floor .find, inject(0)...

Ken Kunz: how to use "benchmark" , .step ,easy to understand...

Ara.T.Howard: how to write a benchmark, fork, subprocess, lambda(Proc), label ,Inline C

Josef 'Jupp' SCHUGT: best algorithm so far , array.push...

Ryan Davis:-rzenoptimize
Issues: 1) I installed zenhacks and RubyToC in order to run -rzenoptimize but failed. I will work on that later.

2) I installed win32-process to implement the "fork" method, failed. I will work on that later.

BTW, To prove nothing , just for fun, here is the results from the final version (from Josef 'Jupp' SCHUGT, i changed a little bit)

My original one: 101 seconds.

The final one: 0.48 seconds

Perl CPAN version: 5 seconds (only means the algorithm is not good)

So if Josef put his version in RAA , the Ruby RAA "primes" will 10 times faster than the perl CPAN one for the time being. :o)

class Integer

def primes

f=2

p=[] if self <2

p=[2] if self >=2

3.step(self, 2) do |i|

r = Math.sqrt(i).to_i

p.each { |f| break if (i%f).zero? or f > r}

p.push(i) if (i%f).nonzero?

end # end the do block

return p

end

end

a=Time.now.to_f

puts 50000.primes.length

printf "time taken %.2f seconds", Time.now.to_f-a

Perl CPAN:

use Math::Big 'primes';

my $max = 50000;

my $start = time();

my $total = primes($max);

my $time = time() - $start;

print "There are $total primes below $max.\n";

print "Time taken was $time seconds\n";

···

---------------------------------
Yahoo! Sports
Rekindle the Rivalries. Sign up for Fantasy Football

Michael Tan wrote:

So if Josef put his version in RAA , the Ruby RAA "primes" will 10 times faster than the perl CPAN one for the time being. :o)

That's not necessary, it's already part of the standard library:

require 'mathn'
p Prime.new.inject(0) { |s,x| if x > 50_000 then break s else s + 1 end }

···

--
Florian Frank

Michael Tan wrote:

Thank you for everyone who replied my first post with my first Ruby program here directly or indirectly. It is really a great community, a lot of fun. I did not expect I could learn so much. Here are some of I learned from everyone: 1) everything is object,so all are method calls (to_i, to_f, each, ...) . 2)open class even for Integer, String... ,.3) method chain , 4) .yield and code block and more.

It's funny how, with everybody's answers on how to make the Ruby code faster, what you got out of it was the flexibility of Ruby. That's 'cause Ruby's the man. Also 'cause, apparently, speed isn't your only concern.

Sorry. Don't really have anything to say here. Just was glad to see you got your priorities straight. Ruby *is* beatiful. :slight_smile:

OK, I promise. My next post will be informative or helpful or something.

Devin
Emphasis on "something."

For comparison, the port of your code to (less than elegant) C#.
Timings done with a release build against .NET 1.1 on Windows XP (P4
2.8/800/HT). New to the list, so hopefully I'm not dup'ing someone
else. (I adjusted the Ruby version slightly to move the puts call
outside the timing loop for code parity, which not surprisingly cut
off 0.03s from the Ruby running time.)

C:\>ruby primes.rb
5133
time taken 0.44 seconds

C:\>primes
5133
Time taken: 00:00:00.0156250

~ ~ ~

using System;
using System.Collections;

public class Primes
{
  public static ArrayList CalcPrimes(int val)
  {
    ArrayList results = new ArrayList();

    if (val < 2)
      return results;

    results.Add(2);

    for (int i = 3; i < val; i += 2)
    {
      int r = (int) Math.Sqrt(i);
      int f = 0;

      for (int idx = 0; idx < results.Count; idx++)
      {
        f = (int) results[idx];
        if ((i % f) == 0 || f > r)
          break;
      }

      if ((i % f) != 0)
        results.Add(i);
    }

    return results;
  }

  public static void Main()
  {
    DateTime start = DateTime.Now;
    ArrayList primes = CalcPrimes(50000);
    TimeSpan taken = DateTime.Now - start;
    Console.WriteLine(primes.Count);
    Console.WriteLine("Time taken: {0}", taken);
  }
}

class Integer
def primes
f=2
p= if self <2
p=[2] if self >=2
3.step(self, 2) do |i|
r = Math.sqrt(i).to_i
p.each { |f| break if (i%f).zero? or f > r}
p.push(i) if (i%f).nonzero?
end # end the do block
return p
end
end

To make shorter/clearer(?) replace

     p= if self <2
     p=[2] if self >=2

with

     p = self > 1 ? [2] :

Yeah, but that way's pretty slow.

joe@ubuntu:~/repos/playground/ruby $ cat primes.rb
require 'mathn'
class Integer
    def primes
        f=2
        p= if self <2
        p=[2] if self >=2
        3.step(self, 2) do |i|
            r = Math.sqrt(i).to_i
            p.each { |f| break if (i%f).zero? or f > r}
            p.push(i) if (i%f).nonzero?
        end # end the do block
        return p
    end
end

a=Time.now.to_f
puts 50000.primes.length
printf "time taken: %.2f seconds\n", Time.now.to_f-a

# Florian's version
b = Time.now.to_f
puts Prime.new.inject(0) { |s, x| if x > 50000 then break s else s + 1 end }
printf "time taken: %.2f seconds\n", Time.now.to_f-b

joe@ubuntu:~/repos/playground/ruby $ ruby primes.rb
5133
time taken: 0.47 seconds
5133
time taken: 13.16 seconds

···

On 6/25/05, Florian Frank <flori@nixe.ping.de> wrote:

Michael Tan wrote:

>So if Josef put his version in RAA , the Ruby RAA "primes" will 10 times faster than the perl CPAN one for the time being. :o)
>
>
That's not necessary, it's already part of the standard library:

require 'mathn'
p Prime.new.inject(0) { |s,x| if x > 50_000 then break s else s + 1 end }

Brad Wilson wrote:

For comparison, the port of your code to (less than elegant) C#.
Timings done with a release build against .NET 1.1 on Windows XP (P4
2.8/800/HT).

And what if you Use C# 2 features like generics and Array.Map?

I vote for shorter, not clearer.

···

On 6/26/05, jzakiya@mail.com <jzakiya@mail.com> wrote:

> class Integer
> def primes
> f=2
> p= if self <2
> p=[2] if self >=2
> 3.step(self, 2) do |i|
> r = Math.sqrt(i).to_i
> p.each { |f| break if (i%f).zero? or f > r}
> p.push(i) if (i%f).nonzero?
> end # end the do block
> return p
> end
> end

To make shorter/clearer(?) replace

     p= if self <2
     p=[2] if self >=2

with

     p = self > 1 ? [2] :

With Ruby 1.8.2, Mandriva LE 2005, AMD K-7, 600MHz
Testing with 1_000_000.primes

Found this to be infintesimally faster:

       p.each { |f| break if (i%f).zero? or f > r }
       next if (i%f).zero?
       p.push(i)
     end

than this

       p.each { |f| break if (i%f).zero? or f > r }
       p.push(i) if (i%f).nonzero?
     end

Joe Van Dyk wrote:

Yeah, but that way's pretty slow.

It get's faster the second time you do it.

···

--
Florian Frank

Joe Van Dyk wrote:
[...]

And my output of your program is:

5133
time taken: 0.86 seconds
5133
time taken: 0.44 seconds

What's wrong with your computer?

···

--
Florian Frank

I can give that info tomorrow when I'm at work (where I have a Whidbey
beta 2 VM). You have to assume 2.0 is slightly faster, because there's
a lot of boxing going on in the 1.1 version.

···

On 6/26/05, Florian Groß <florgro@gmail.com> wrote:

And what if you Use C# 2 features like generics and Array.Map?

I realy dont think that language choice weighs anything when there is a
better algorithm available: the Atkin sieve. Sample implentation in C
generates the 50847534 primes up to 1000000000 in just 8 seconds on a
Pentium II-350. It is not that was implented in C, rather the algorithm
used O(n/log(log(n))) instead of the vairous 'optimized' but basicaly
inferiour Sieve of Eratosthenes disussed here.

There is also a primegen library making with a clean interface, so with
a bit of SWIG magic you can call this beast from Ruby too.

···

---
http://deezsombor.blogspot.com/

I'm not sure what "Array.Map" is. The Whidbey beta 2 docs didn't show
a method off of Array or Array<> named Map.

Replacing ArrayList with List<int> resulted in identical execution
times for 50,000 items, so I presumed it was a statistically
insignificant sampling (using DateTime.Now is a very low res way of
finding time differences, and anything under 1s is probably suspect
anyway).

I ran 5 million. Non-generic .NET is ~ 50x faster than Ruby (probably
was before too, but we couldn't tell because of the smallish sample
size). Generic .NET ran ~ 1.2x faster than non-generic .NET. All
things considered, that's a decent showing for interpreted/latent
typed vs. JITted/strong typed.

C:\> ruby primes.rb
348513
time taken 197.84 seconds

C:\> primes.exe
348513
Time taken: 00:00:04.0000512

C:\> primes-generic.exe
348513
Time taken: 00:00:03.3125424

···

On 6/26/05, Florian Groß <florgro@gmail.com> wrote:

And what if you Use C# 2 features like generics and Array.Map?

I think this shows the speed of my computer more than anything else:

C:\dev>ruby primes.rb
5133
time taken: 2.06 seconds
5133
time taken: 41.82 seconds
Florian again
5133
time taken: 41.86 seconds

Appending this:

puts 'Florian again'

# Florian's version
b = Time.now.to_f
puts Prime.new.inject(0) { |s, x| if x > 50000 then break s else s + 1 end }
printf "time taken: %.2f seconds\n", Time.now.to_f-b

To test this:

>Yeah, but that way's pretty slow.
>
It get's faster the second time you do it.

Douglas

···

On 6/26/05, Florian Frank <flori@nixe.ping.de> wrote:

Joe Van Dyk wrote:
[...]

And my output of your program is:

5133
time taken: 0.86 seconds
5133
time taken: 0.44 seconds

What's wrong with your computer?

--
Florian Frank

Brad Wilson wrote:
-snip-

I ran 5 million. Non-generic .NET is ~ 50x faster than Ruby (probably
was before too, but we couldn't tell because of the smallish sample
size).

For simple Ruby and C# Sieve implementations, on The Great Computer
Language Shootout, Mono C# was ~48x faster than Ruby

http://shootout.alioth.debian.org/great/benchmark.php?test=all&lang=ruby&lang2=csharp&sort=fullcpu#ratio

http://shootout.alioth.debian.org/great/benchmark.php?test=nsieve&lang=all&sort=fullcpu#bench

···

Generic .NET ran ~ 1.2x faster than non-generic .NET. All
things considered, that's a decent showing for interpreted/latent
typed vs. JITted/strong typed.

C:\> ruby primes.rb
348513
time taken 197.84 seconds

C:\> primes.exe
348513
Time taken: 00:00:04.0000512

C:\> primes-generic.exe
348513
Time taken: 00:00:03.3125424

My algorithmic ramblings gone unheard ... for performance language
matters less!

Try to run for the first 1_000_000_000 numbers with any language on any
hardware with any kind of varitions on Erastothenes sieve. And see if
you can beat the 8 second mark produced with an obsolete Pentium II 350
Mhz that uses the Atkin sieve. See http://cr.yp.to/primegen.html.

···

---
http://deezsombor.blogspot.com

Brad Wilson wrote:

And what if you Use C# 2 features like generics and Array.Map?

I'm not sure what "Array.Map" is. The Whidbey beta 2 docs didn't show
a method off of Array or Array<> named Map.

Ah, sorry, I should have checked back with the documentation. It's actually called Array.ConvertAll:

···

            int numbers = { 1, 2, 3 };
            string newNumbers = Array.ConvertAll<int, string>(
                numbers,
                delegate(int number) { return (number + 1).ToString(); });
            System.Console.WriteLine(String.Join(", ", newNumbers));

I always got the almost same results on my laptop: (Pentium M 1.5G, 1G ram). I closed all other programs, Excel, Eclipse, browsers, ...before I ran it.
C:\temp>ruby test.rb

5133
time taken 0.49 seconds
###### RAA ..###################################
5133
time taken 36.51 seconds
5133
time taken 36.67 seconds
5133
time taken 36.49 seconds

I think this shows the speed of my computer more than anything else:

C:\dev>ruby primes.rb
5133
time taken: 2.06 seconds
5133
time taken: 41.82 seconds
Florian again
5133
time taken: 41.86 seconds

Appending this:

puts 'Florian again'

# Florian's version
b = Time.now.to_f
puts Prime.new.inject(0) { |s, x| if x > 50000 then break s else s + 1 end }
printf "time taken: %.2f seconds\n", Time.now.to_f-b

To test this:

>Yeah, but that way's pretty slow.
>
It get's faster the second time you do it.

Douglas

···

Douglas Livingstone <rampant@gmail.com> wrote:

On 6/26/05, Florian Frank wrote:

Joe Van Dyk wrote:
[...]

And my output of your program is:

5133
time taken: 0.86 seconds
5133
time taken: 0.44 seconds

What's wrong with your computer?

--
Florian Frank

__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around

I agree with this. I also subscribe to the YAGNI performance
principal: there are whole classes of problems for which computational
performance is of minimal impact. For instance, imagine an n-tier
architecture web application with separated web servers and database
servers. The time spent talking to the database over the network
dwarfs the nanoseconds of "loss" in using an interpreted language.

If I didn't believe this, I wouldn't be a Ruby fan. :wink:

···

On 6/28/05, Dee Zsombor <Dee.Zsombor@gmail.com> wrote:

My algorithmic ramblings gone unheard ... for performance language
matters less!