On Wednesday, August 23, 2017 at 3:40:48 PM UTC-5, luser droog wrote:
> On Wednesday, August 23, 2017 at 3:38:55 PM UTC-5, luser droog wrote:
> > On Wednesday, August 23, 2017 at 3:33:07 PM UTC-5, luser droog wrote:
> > > On Wednesday, August 23, 2017 at 3:10:48 PM UTC-5, luser droog wrote:
> > > > I'm not getting the speed-up I expected from this memo-izing
> > > > fibonacci program. it'll do 1 to 20 in .5 seconds, but even
> > > > with a generous dictionary 1 to 25 takes 4.sthg seconds.
> > > >
> > > > real 0m4.060s
> > > > user 0m3.671s
> > > > sys 0m0.061s
> > > >
> > >
> > >
> > > Umm... ignore the previous code ... if you can. Here's an improved
> > > version which demonstrates the same thing. I feel like it should be
> > > faster.
> > >
> >
> > OMG. Duh. It never updates the dict with new values.
>
>
> Here we go. Much better results now.
>
>
> real 0m0.173s
> user 0m0.077s
> sys 0m0.061s
>
For the benefit of spectators, here's some additional commentary.
> Norah@laptop ~
> $ cat
memo.ps
> %!
We start with two procedures /pusherr and /poperr which provide
the capability of stacking error handlers. They're a little weird
because they use the regular operand stack as the stack as well
as using the stack for argument passing. So /pusherr, after a
casual glance at the stack effect comment, might appear not to
do anything useful at all. But it installs the new handler given
as an argument and returns the old handler. And /poperr takes
an argument handler and simply installs it.
Don't worry. It /is/ confusing.
>
> <<
> /pusherr { % /errname {handler} --> /errname {old-handler}
> errordict 3 1 roll % d n p
> 3 copy pop get % d n p op
> 2 index exch 5 2 roll put
> }
>
> /poperr { % /errname {handler}
> errordict 3 1 roll put
> }
>
I probably could factor it to use /poperr in the code for /pusherr.
Or something internally complicated, maintaining a stack data structure,
in exchange for a cleaner interface... hmmm....
On to the meat, ...
> /memo-func {
> {
> DICT begin
> /undefined { pop dup default dup 3 1 roll def } pusherr 3 2 roll
> load
> 3 1 roll poperr
> end
> }
> dup length array copy
> dup 3 2 roll 0 exch put cvx
> }
> >> begin
>
If you've been following my other recent threads, the idea should
be familiar. It's generating a procedure body specified by the
template but with the DICT replaced by the dict argument.
The resulting procedure simply pushes the local dict (again this
should be familiar), then pushes an error handler for the /undefined
error, then just does `load`, and pops the handler and the dict.
The error handler calls the procedure named /default and saves
the input and output as a new definition in the local dict.
>
> /fib <<
> 0 1
> 1 1
> /default { dup 2 sub fib exch 1 sub fib add }
> >> 100 dict copy memo-func def
>
> 0 1 25 { fib = } for
>
And the usage. Pretty close to the textbook mathematical form, I think.
fib(x) = { 0 -> 1
| 1 -> 1
{ fib(x-2) + fib(x-1)
And it runs, produces good looking results, and pretty fast! Hurray!