[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

Re: [FWP] Ackerman





Abigail wrote:
> On Wed, Jun 27, 2001 at 10:47:37AM +0100, csaba.raduly@sophos.com wrote:
> > Do you think your computer has too much memory ? Give it a workout!
[snip my script using the following formula]
> > sub Acker
> > {
> >    my ( $m, $n ) = @_;
> >    if( $m==0 ){
> >       return $n+1;
> >    }
> >    if( $n==0 ){
> >       return Acker( $m-1, 0 );
                              ^
This should be 1, not 0 ------^

> >    }
> >    return Acker( $m-1, Acker($m,$n-1) );
> > }
> >
> > This script computes the Ackerman function, The Most Fiendishly
Recursive
> > Function Known To Man (tm).
>
> Eh, no, it doesn't. It starts off with:
>
>         A( 1, 0 ) = 2
>                         1,1
>         A( 1, 1 ) = 3
>                         1,2
>         A( 1, 2 ) = 4
>                         1,3
>         A( 1, 3 ) = 5
>                         1,4
>         A( 1, 4 ) = 6
>                         1,5
>         A( 1, 5 ) = 7
>                         1,6
>         A( 1, 6 ) = 8
>                         1,7
>         A( 1, 7 ) = 9
>                         1,8
>
> which are numbers that are way too low.  The rest of the numbers are
> way too low too.

At least the results above *are* correct. Purely by accident :-(

A(0,n) = n+1           =  n + 1
A(1,n) = 2 + (n+3) - 3 =  n + 2
A(2,n) = 2 * (n+3) - 3 = 2n + 3
A(3,n) = 2 **(n+3) - 3

See for example http://public.logica.com/~stepneys/cyc/a/ackermnn.htm

> Acker (3, 5) for instance is a number with almost
> 20k digits.

Nope, Acker(3,5) = 2**(5+3) - 3 = 253
Acker(3,5) = A( 2, A(3,4) ) = A( 2, 125 ) = A( 1, A(2,124) )

It's A( 4,2 ) which has 19729 digits.

>
> Your program puzzles me. You have a function 'Acker', but you never call
> it.

That's the legible implementation. Sub A is using the ?: operator,
and I needed the plain one to figure it out :-)

Unfortunately, there was a typo in the plain one :-(

> You also use Math::BigInt, but you never make objects from that class.
>

You mean "use Math::BigInt" doesn't work like "use integer" ?
Damn.

>
> Here's an implementation of the Ackermann function, as defined in [1].
> Call the program with two arguments, indicating the max arguments with
> call the Ackermann function with, and an optional first "-OPTIMIZE",
> which heavily optimizes the calculation of the values.
>
>
> [1] Edelsbrunner, Herbert: "Algorithms in Combinatorial Geometry", in
>     Brauer, W., Rozenberg, G., and Salomaa, A. (Eds.) "EATCS Monographs
>     on Theoretical Computer Science", Berlin: Springer-Verlag, 1987,
>     pp 377.
>
>
> #!/opt/perl/bin/perl -ws
>
> use strict;
> use Math::BigInt;
>
> my $two    = Math::BigInt -> new (2);
> my $three  = Math::BigInt -> new (3);
> my $four   = Math::BigInt -> new (4);
>
> use vars qw /$OPTIMIZE/;
>
> sub Ack {
>     my ($i, $j) = @_;
>
>     if ($OPTIMIZE) {
>         return $four                        if $j == 2;
>         return $two *  $j                   if $i == 1;
>         return $two ** $j                   if $i == 2;
>         return $two ** Ack ($three, $j - 1) if $i == 3 && $j >= 2;
>     }
>
>     return $two if $j == 1;
>     return Ack ($i, $j - 1) + $two if $i == 1;
>
>     Ack ($i - 1, Ack ($i, $j - 1))
> }

Are we speaking about different Ackermann functions ?
Is this what you're implementing ?

__recursion formula___           __function__
A(  0,  n) = n+1                 A(0, n) = n+1
A(m+1,  0) = A(m, 1)             A(m, 0) = A(m-1, 1)
A(m+1,n+1) = A(m, A(m+1,n))      A(m, n) = A(m-1, A(m,n-1))


Here's another try, using your "OPTIMIZE" idea,
hardwired to always:

sub Ack {
    my ($i, $j) = @_;

    return $j+1                    if $i == 0;
    return $j+2                    if $i == 1;
    return $two * $j + $three      if $i == 2;
    return $two ** ($j+3) - $three if $i == 3;

    # now $i > 3 and the fun begins
    return Ack( $i-1, 1 )          if $j == 0;
    return Ack( $i-1,
                Ack( $i, $j-1 ) );
}

>
> my $i_max = shift || 4;
> my $j_max = shift || 3;
>
> foreach my $I (1 .. $i_max) {
>     my $i = Math::BigInt -> new ($I);
>     foreach my $J (1 .. $j_max) {
>         my $j = Math::BigInt -> new ($J);
>         print "Ack ($i, $j) = ", Ack ($i, $j), "\n";
>     }
> }
>
> __END__
> $ ./ack -OPTIMIZE 5 5
> Ack (+1, +1) = +2
> Ack (+1, +2) = +4
> Ack (+1, +3) = +6
> Ack (+1, +4) = +8
> Ack (+1, +5) = +10
> Ack (+2, +1) = +2
> Ack (+2, +2) = +4
> Ack (+2, +3) = +8
> Ack (+2, +4) = +16
> Ack (+2, +5) = +32
> Ack (+3, +1) = +2
> Ack (+3, +2) = +4
> Ack (+3, +3) = +16
> Ack (+3, +4) = +65536
> Ack (+3, +5) = BIGNUM

All your results are wr^H^Hdifferent !
Replacing Ack with mine, and making the loops start at 0, this is what I
got:
(See attached file: rezult)


--
Csaba Ráduly, Software Engineer                     Sophos Anti-Virus
email: csaba.raduly@sophos.com                  http://www.sophos.com
US support: +1 888 SOPHOS 9               UK Support: +44 1235 559933

=?iso-8859-1?Q?rezult?=