On Wednesday 25 November 2009 10:01:02 am Ralph S. wrote:
Is there a document or website that describes how Ruby works?
You’re going to have to get a lot more specific.
y=0
1_000_000.times {|x| y+=x}
(1) Does the block get compiled a million times?
Implementation-specific, but I doubt it.
(2) What’s the best Ruby way to do a sum from 1 to 1_000_000
What do you mean by “best”? Your way probably won’t work, by the way –
it
will count from 0 to 999_999, not from 1 to 1_000_000.
This is probably the most idiomatic way:
(1…1_000_000).inject(&:+)
But if you mean the fastest way, I would guess it would be something
like
this, in pure ruby:
y = 0
i = 0
while i < 1_000_000
i += 1
y += i
end
Realistically, though, Ruby probably isn’t the best language. Inline C
might
be better:
require ‘inline’
class Foo
inline do |builder|
builder.c <<-END
long sum(long max) {
long result = 0;
long i;
for(i=1; i<=max; i++) {
result += i;
}
return result;
}
END
end
end
puts Foo.new.sum(1_000_000)
To be fair, this takes longer on my system, but I think that’s because
the C
compiler is being run each time. I’m sure there’s a way to avoid that,
but I
haven’t looked. This is also going to be much more difficult for you on
Windows than, well, any other platform.
But you should keep some things in mind – this is a really arbitrary
benchmark, of the sort that you’d never actually use in real code.
Try this instead:
n = 1_000_000
n*(n+1)/2
The way to be faster in any language is to improve your algorithm – and
your
algorithm is much more likely to be a bottleneck than the language in
question. That’s why I use Ruby in the first place.
(3) Is there a difference in speed between IRB.exe and ruby.exe in
executing the above code?
Maybe. If both are from the same version of Ruby, there shouldn’t be
anything
significant. You could test it, though.
(4) In IRB, whats the best way to time the code, above?
The simplest way is:
require ‘benchmark’
require ‘foo’ # if you do the RubyInline example I gave
Benchmark.bm do |x|
x.report { Foo.new.sum(1_000_000) }
x.report { y = 0; 1_000_001.times {|x| y += x} }
x.report { (1…1_000_000).inject(&:+) }
x.report { n = 1_000_000; n*(n+1)/2 }
end
That’ll work anywhere, though it’s going to be a bit cumbersome in irb.
Someone else may have a “best” way.
I haven’t run this test, though. I have no plans to, unless someone
really
wants to claim that any of the loops are faster than those three integer
operations.