When Perl calls a recursive function it does a huge amount of work saving state, optimizing the next time you call it, etc. For a sobering comparison, compare the implementation above with the following one where I manage a stack explicitly instead of having a stack of function calls:
sub A {
my ($x, $y) = @_;
my @stack = ();
while (1) {
if (0 == $x) {
if (@stack) {
$y++;
$x = pop(@stack);
}
else {
return 1 + $y;
}
}
else {
if (0 == $y) {
$x--;
$y = 1;
}
else {
push @stack, $x-1;
$y--;
}
}
}
}
Impressed? | [reply] [d/l] |
| [reply] |
If you understand the growth pattern properly, you will realize that A(4,3) is not running with the naive algorithm in your lifetime on a computer, and even if it did, Perl would be unable to represent the answer.
Try A(3,6), A(3,7) and A(3,8) to get an idea of relative performance.
Now if you really want a speed boost, what you want to do isn't make the recursion faster, but rather insert more and more special cases to avoid spending all of the time recursing at the tail. The following executes acceptably:
sub A {
BARE_BLOCK: {
if (0 == $_[0]) {
return 1 + $_[1];
}
elsif (1 == $_[0]) {
return 2 + $_[1];
}
elsif (2 == $_[0]) {
return 3 + 2*$_[1];
}
@_=($_[0] - 1, $_[1] ? A($_[0], $_[1]-1) : 1);
redo BARE_BLOCK;
}
}
And here we find out why to use recursion even if Perl is bad at it. This intelligent optimization would be very hard to write if you first did the low-level optimization of avoiding any recursive calls. Intelligent algorithms beat faster execution of bad ones any time! | [reply] [d/l] |
Sorry. Perl can't detect tail-end recursion for you. In fact Perl's handling of deep recursion is truly horrible.
As for whether my answers are right or wrong, they agree with this page... | [reply] |
The version of the function I was using is expressed cleanly by VSarkiss in this node. It gives 65536.
The Perl code reads exactly from the piece definition, adding a few $ symbols, a *, and semi's. It makes every condition explicit, and don't rely on narrowing constraints and order of definition. So I'm pretty sure that's a correct implementation.
I suppose there are multiple versions of Ackerman's idea, all working in the same way, but different in detail.
—John
| [reply] |
| [reply] |