[REBOL] Re: Benchmarking alternatives
From: joel:neely:fedex at: 6-Nov-2001 14:54
Ryan Cole wrote:
> ... Do you know of a way I can take advantage of this gain
> inside a block?
>
> >> blk: []
> == []
> >> append/only blk to-paren [1 + 1]
> == [(1 + 1)]
> >> b/1
> == (1 + 1)
> >> append/only blk does [1 + 1]
> == [(1 + 1) func [][1 + 1]]
> >> b/2
> == 2
> >>
>
(I assume you meant to use BLK instead of B, which interestingly
seems to be synonymous??? Oh, well, back to your question...)
I don't know any way to get the paren evaluated without some
additional overhead, which (of course) defeats the whole idea.
Obviously, given
>> blk: []
== []
>> append/only blk to-paren [1 + 1]
== [(1 + 1)]
>> append/only blk does [2 + 2]
== [(1 + 1) func [][2 + 2]]
one could use any of the following
>> reduce blk
== [2 4]
or
>> do blk/1
== 2
or, oddly enough,
>> x: blk/1
== (1 + 1)
>> x
== 2
Maybe someone else has a trick or two that can help here...
Meanwhile, my target was the kind of thing where one constructs or
selects a block to be DOne later, or uses such a block to build
a DOES function. A dinky example might help illustrate...
Consider the task of summing up the reciprocals of some positive
integers *or* summing the reciprocals of their squares (depending
on the presence of a switch). The brute-force solution
tally-inside: func [limit [integer!] /squares /local t] [
n: t: 0
while [n < limit] [
n: n + 1
either squares [
t: 1.0 / n / n + t
][
t: 1.0 / n + t
]
]
t
]
keeps making the same decision over and over and over and ...
The first (commonly-seen) optimization is to move the decision
out of the loop by constructing/selecting a block to be repeated,
doing this prior to the beginning of the loop.
tally-outside: func [limit [integer!] /squares /local t incr] [
incr: either squares [[
t: 1.0 / n / n + t
]][[
t: 1.0 / n + t
]]
n: t: 0
while [n < limit] [n: n + 1 do incr]
t
]
This give a time savings of a few percent. OTOH, constructing a
paren to hold (and evaluate) the appropriate expression, as in:
tally-paren: func [limit [integer!] /squares /local t incr] [
incr: to-paren either squares [[
t: 1.0 / n / n + t
]][[
t: 1.0 / n + t
]]
n: t: 0
while [n < limit] [n: n + 1 incr]
t
]
saves more. Interestingly enough, using the paren for only a
*part* of the expression, as in:
tally-recip: func [limit [integer!] /squares /local t term] [
term: to-paren either squares [[ 1.0 / n / n ]][[ 1.0 / n ]]
n: t: 0
while [n < limit] [n: n + 1 t: term + t]
t
]
provides yet another competitive option.
Of course, I'm well aware that there are other ways to perform
this *particular* computation, but the point was to focus on how
to pull a decision out of a loop. I chose a simple example, not
because I couldn't think of other ways to do this piece of
arithmetic, but to illustrate the refactoring without bogging
down in a complicated example.
-jn-
--
It's amazing how polific Ibid was.
-- Amy Johnson
joel'dot'neely'at'FIX'PUNCTUATION'fedex'dot'com