Ruby speed compared to C in a simple calculations

#works for 3.55 mins
P = 295075153
o1 = 210205973
o2 = 22795300
(0 .. P).each do | i |
    if i ^ (i ^ o1) == o1 and ((i * 2 + 5) % P) ^ (((i ^ o1) * 3 + 7) % P)
== o2
        puts i
        break
    end
end
Code written in C gives me the solution in only 2 seconds. I suppose that
it's called not by ruby slowlyness, but my shitty coding abilities. Cuold
tou please tell me the weaknesse of the code?

W dniu 24 marca 2012 17:45 użytkownik Роман Ткаленко
<rain.roman@gmail.com> napisał:

#works for 3.55 mins
<snip>
Code written in C gives me the solution in only 2 seconds. I suppose that
it's called not by ruby slowlyness, but my shitty coding abilities. Cuold
tou please tell me the weaknesse of the code?

It took 51 seconds for me on Ruby 1.9.3, on a laptop; the 1.9 series
is much faster than 1.8.

Ruby, overall, is unfortunately very slow. There are many reasons for
this (for example, every operator is your code becomes a method call,
and every method call requires looking up the relevant code in a
method table - this adds up), and not much can be done.

For some reason even the bare "(0 .. P).each do | i |" loop (with
everything inside removed) takes 30 seconds to run, and so does a
P.times or a while loop (negligible time difference). You just can't
do fast computation in Ruby now, at all. (Note that JRuby or Rubinius
might be faster for numeric computation - try yourself, if you care.)

-- Matma Rex

"Роман Ткаленко" <rain.roman@gmail.com> wrote in post #1053071:

#works for 3.55 mins
P = 295075153
o1 = 210205973
o2 = 22795300
(0 .. P).each do | i |
    if i ^ (i ^ o1) == o1 and ((i * 2 + 5) % P) ^ (((i ^ o1) * 3 + 7) %
P)
== o2
        puts i
        break
    end
end
Code written in C gives me the solution in only 2 seconds.

Does the C code just use int64's? In ruby, integer values transparently
extend from Fixnum to Bignum, so there's never any overflow. But this
means that every integer value is an object and there has to be dynamic
method dispatch for each arithmetic operation.

You can always embed snippets of C into Ruby - look at RubyInline.

···

--
Posted via http://www.ruby-forum.com/\.

ruby is extremly flexable ... and you paid this freedom with speed ...
(but you can write some methods in C for ruby)

···

--
Posted via http://www.ruby-forum.com/.

It's not shitty coding (though I do find your code unreadable). It's
because C is compiled into assembly, when you tell it to iterate that many
times, it can put the number directly into a register and decrement the
value. Ruby is much higher level than that. Numbers are actual objects that
must be allocated, for example. So an example like this, C is going to
dramatically outperform Ruby.

Like anything, there are tradeoffs. For instance, by representing numbers
with just binary values that fit into C's int type, you your program up to
the limitations of that type (e.g. in Ruby you can have arbitrarily large
numbers `$ruby -e 'p 2**2000'`).

And, of course, the Ruby version uses a closure. ANSI C doesn't have
closures, which prevents it from being able to support very powerful coding
styles (i.e. many of the things Lisp is famous for).

So, really its best to figure out what your domain is and find a language
well suited to that. If your domain is hardcore number crunching, then Ruby
is probably not the best choice (though I did solve a number of Project
Euler problems with it).

-Josh

···

On Sat, Mar 24, 2012 at 11:45 AM, Роман Ткаленко <rain.roman@gmail.com>wrote:

#works for 3.55 mins
P = 295075153
o1 = 210205973
o2 = 22795300
(0 .. P).each do | i |
    if i ^ (i ^ o1) == o1 and ((i * 2 + 5) % P) ^ (((i ^ o1) * 3 + 7) % P)
== o2
        puts i
        break
    end
end
Code written in C gives me the solution in only 2 seconds. I suppose that
it's called not by ruby slowlyness, but my shitty coding abilities. Cuold
tou please tell me the weaknesse of the code?

Your version on JRuby:

* JRuby master (1.7) on OpenJDK 6: 1m44s
* JRuby master (1.7) on OpenJDK 7 (1.7.0_04): 35s

A modified version (while loop, no constant, body of code in a method)
on JRuby runs in 30s. That's close to a theoretical maximum for JRuby
right now without JVM help (since we have to allocate all those Fixnum
objects).

Our new optimizing compiler will definitely be able to improve on
this, since it may be able to use actual primitives for self-contained
numeric algorithms.

- Charlie

···

On Sat, Mar 24, 2012 at 11:45 AM, Роман Ткаленко <rain.roman@gmail.com> wrote:

#works for 3.55 mins

W dniu 24 marca 2012 18:55 użytkownik Josh Cheek <josh.cheek@gmail.com> napisał:

Numbers are actual objects that must be allocated, for example.

Fun fact: it's thankfully not *that* bad. Numbers up to 2**30-1 are
not actually allocated; instead, they're magically stored in the C
pointer which would normally point at the location of associated
object. Symbols are handled similarly (that's why you should always
use them instead of strings when the actual string values does not
matter).

See for yourself. For regular objects, #object_id returns numerical
values of location in memory where it is stored (that is, values of C
pointer to this object). But...

irb(main):001:0> 1.object_id
=> 3
irb(main):003:0> 100.object_id
=> 201
irb(main):005:0> 120.object_id
=> 241
irb(main):007:0> 200.object_id
=> 401

Here you see a pattern: small numbers' object_id are equal to the
number, doubled, plus one.

irb(main):015:0> 2**30-1
=> 1073741823
irb(main):016:0> (2**30-1).object_id
=> 2147483647
irb(main):017:0> (2**30-1).class
=> Fixnum

The pattern still holds.

irb(main):018:0> 2**30
=> 1073741824
irb(main):019:0> (2**30).object_id
=> 6594348
irb(main):020:0> (2**30).class
=> Bignum

No more! Our number was promoted to a Bignum, which is actually
allocated separately - the object_id value is no longer magical, it's
just a straight pointer to a location in memory. (It will be different
on your machine.)

-- Matma Rex