"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:m3y8kv2qx2.fsf@asfast.com...
First of all, I very much thank all of you who responded to my query.
I've
read all of your useful and helpful replies, but I am only responding to
this final one, so as to minimize bandwidth.
"Robert Klemme" <bob.news@gmx.net> writes:
> [ ... ]
>
> require 'benchmark'
> include Benchmark
>
> str = "Hammer and tongs"
>
> bm(7) do |x|
> x.report("1") { 100000.times { str.reverse.split(//).each { |ch|
> ch } } }
> x.report("2") { 100000.times { str.reverse.split('').each { |ch|
> ch } } }
> x.report("3") { 100000.times { str.reverse.each_byte { |ch|
ch.chr } } }
> x.report("4") { 100000.times { (str.length-1).downto(0) {|idx| ch =
> str[idx]} } }
> x.report("5") { 100000.times { len = str.size; for idx in 1..len ;
ch =
> str[len-idx] end } }
> end
> user system total real
> 1 6.828000 0.000000 6.828000 ( 6.907000)
> 2 6.891000 0.000000 6.891000 ( 6.936000)
> 3 5.078000 0.000000 5.078000 ( 5.098000)
> 4 2.281000 0.000000 2.281000 ( 2.287000)
> 5 3.391000 0.000000 3.391000 ( 3.395000)
I have been so steeped in Ruby-ish thinking that I had completely
forgotten about array indexing. Duh!

And being so reminded, at first I would not have suspected that the
algorithms based on indexing would be faster than the others. But I
suspect that the absence of 'reverse' is what accounts for the speed
differences.
The most costly operations are object creations (apart from Fixnums which
AFAIK are handled a bit differently). From that it's clear that
reverse.split is extremely costly since there are n + 2 instances created
(1 Array, 1 reverse String, n Strings with length 1).
By the way, I tried this with longer strings: between 40 and 8192 bytes,
which are the most likely lengths for the strings I will be dealing
with. As the lengths increase beyond something like 50-60 bytes,
algorithm number 5 becomes faster than algorithm 4, and the difference
in speeds keeps increasing with longer strings.
But if I replace "ch.chr" in algorithm 3 and with just "ch" by itself,
that algorithm suddenly becomes the fastest.
Oh, that can happen if you just copy and past. Of course ".chr" must be
removed in order to get comparable results.
The state machine to which
I want to feed the characters can deal with integer representations as
easily as their character equivalents.
Note that there is no character type in Ruby:
"foo"[0].class
=> Fixnum
77.chr.class
=> String
So, it looks like the following
would be the fastest for my purposes:
string.reverse.each_byte {
>c>
feedToMyStateMachine(c)
}
Yep.
Regards
robert
#!/usr/bin/ruby
require 'benchmark'
include Benchmark
str = "Hammer and tongs"
bm(7) do |x|
x.report("1") { 100000.times { str.reverse.split(//).each { |ch|
ch } } }
x.report("2") { 100000.times { str.reverse.split('').each { |ch|
ch } } }
x.report("3") { 100000.times { str.reverse.each_byte { |ch| ch } } }
x.report("4") { 100000.times { (str.length-1).downto(0) {|idx| ch =
str[idx]} } }
x.report("5") { 100000.times { len = str.size; for idx in 1..len ; ch =
str[len-idx] end } }
end
str = "Hammer and tongs" * 10
bm(7) do |x|
x.report("1") { 100000.times { str.reverse.split(//).each { |ch|
ch } } }
x.report("2") { 100000.times { str.reverse.split('').each { |ch|
ch } } }
x.report("3") { 100000.times { str.reverse.each_byte { |ch| ch } } }
x.report("4") { 100000.times { (str.length-1).downto(0) {|idx| ch =
str[idx]} } }
x.report("5") { 100000.times { len = str.size; for idx in 1..len ; ch =
str[len-idx] end } }
end
11:40:07 [ruby]: ./str-reverse.rb
user system total real
1 6.828000 0.000000 6.828000 ( 6.864000)
2 6.937000 0.000000 6.937000 ( 6.926000)
3 1.375000 0.000000 1.375000 ( 1.384000)
4 2.282000 0.000000 2.282000 ( 2.279000)
5 3.422000 0.000000 3.422000 ( 3.412000)
user system total real
1 59.906000 0.000000 59.906000 ( 60.014000)
2 60.250000 0.000000 60.250000 ( 60.420000)
3 10.625000 0.000000 10.625000 ( 10.626000)
4 21.687000 0.000000 21.687000 ( 21.714000)
5 22.422000 0.000000 22.422000 ( 22.455000)