Extremely Deep Recursion - Part 3

The Ackermann function is a computable function which grows very, very quickly as its inputs grow. For example, while A ( 1 , 2 ) , A(1,2), A ( 2 , 2 ) , A (2,2), and A ( 3 , 2 ) A(3,2) are equal to 4 , 7 , 4,7, and 29 , 29, respectively, A ( 4 , 2 ) 2 × 1 0 19728 A(4,2) \approx 2 \times 10^{19728} .

The Ackermann function can be defined as follows: A ( m , n ) = { n + 1 if m = 0 A ( m 1 , 1 ) if m > 0 and n = 0 A ( m 1 , A ( m , n 1 ) ) if m > 0 and n > 0. A(m,n) = \begin{cases} n+1 & \mbox{if } m = 0 \\ A(m-1, 1) & \mbox{if } m > 0 \mbox{ and } n = 0 \\ A(m-1, A(m, n-1)) & \mbox{if } m > 0 \mbox{ and } n > 0. \end{cases}

What are the last 3 digits of A ( 4 , 5 ) ? A(4,5) ?


The answer is 733.

This section requires Javascript.
You are seeing this because something didn't load right. We suggest you, (a) try refreshing the page, (b) enabling javascript if it is disabled on your browser and, finally, (c) loading the non-javascript version of this page . We're sorry about the hassle.

6 solutions

Discussions for this problem are now closed

Thaddeus Abiy
Feb 15, 2014

It is possible to prove the following properties of A ( m , n ) A(m,n) for m < 3 m<3

A ( 0 , n ) = n + 1 A(0,n)=n+1

A ( 1 , n ) = n + 2 A(1,n)=n+2

A ( 2 , n ) = 2 n + 3 A(2,n)=2n + 3

A ( 3 , n ) = 2 n + 3 3 A(3,n)=2^{n+3} - 3

Since A ( 4 , 5 ) A(4,5) is large computing the whole integer would take a while. But since all we need are the last three digits we can just find A ( m , n ) A(m,n) m o d mod 1000 1000 at every recursive call..Ran in 0.001 seconds on my machine.

def A(m,n):
    if m == 0:
        return ( n + 1 ) % 1000
    if m == 1:
        return ( n + 2 ) % 1000
    if m == 2:
        return ( ( ( 2 * n ) + 3 ) ) % 1000 
    if m == 3:
        return ( pow( 2 , n + 3 ) - 3 ) 
    if m >0 and n == 0:
        return ( A( m - 1 , 1 ) ) % 1000
    else:
        return ( A( m - 1 , A( m , n -  1 ) ) ) % 1000

print A(4,5)

Well this would have helped... I wrote a simple function with 3 if statements and it took about 5 minutes to run.

Harshal Sheth - 7 years, 3 months ago

Its mainly because the function doesn't have to deal with the Ackermann function's ridiculously large numbers..

Thaddeus Abiy - 7 years, 3 months ago
Pi Han Goh
Feb 14, 2014

Because m m is rather small, we can use the table given here

A ( 4 , 5 ) = 2 2 2 2 2 2 2 2 eight 2’s 3 \LARGE A(4,5) = \underbrace{2^{2^{2^{2^{2^{2^{2^2}}}}}}}_{\text{eight 2's}} - 3

We consider the last three digits of ( A ( 4 , 5 ) + 3 ) \left ( A(4,5) + 3 \right ) , that is modulo 1000 1000

1000 = 8 × 125 1000 = 8 \times 125 , with 8 8 and 125 125 coprime positive integers, we will use Chinese Remainder Theorem

Denote B = ( A ( 4 , 5 ) + 3 ) B = \left ( A(4,5) + 3 \right ) , because B B has plenty of powers of 2 2 's, so B m o d 8 = 0 B \bmod{8} = 0

With gcd ( 2 , 125 ) = 1 \text{gcd}(2,125) = 1 , Euler Totient Function is applicable, ϕ ( 125 ) = ϕ ( 5 3 ) = 125 ( 1 1 5 ) = 100 \phi(125) = \phi(5^3) = 125 \left ( 1 - \frac {1}{5} \right ) = 100

B m o d 125 = 2 2 2 2 2 2 2 2 m o d 100 m o d 125 \LARGE B \bmod{125} = 2^{2^{2^{2^{2^{2^{2^2}}}}} \bmod {100} } \bmod {125}

Repeat: 100 = 4 × 25 100 = 4 \times 25 , with gcd ( 4 , 25 ) = 1 \text{gcd}(4,25) = 1 , and gcd ( 2 , 25 ) = 1 \text{gcd}(2,25) = 1 , ϕ ( 25 ) = ϕ ( 5 2 ) = 25 ( 1 1 5 ) = 20 \phi(25) = \phi(5^2) = 25 \left ( 1 - \frac {1}{5} \right ) = 20

Denote C = 2 2 2 2 2 2 2 seven 2’s \LARGE C = \underbrace{2^{2^{2^{2^{2^{2^2}}}}}}_{\text{seven 2's}}

C m o d 4 = 0 C \bmod 4 = 0

C m o d 25 = 2 2 2 2 2 2 2 m o d 20 m o d 25 \large C \bmod{25} = 2^{2^{2^{2^{2^{2^2}}}} \bmod{20} } \bmod {25}

Repeat again: 20 = 4 × 5 20 = 4 \times 5 , gcd ( 4 , 5 ) = 1 \text{gcd}(4,5) = 1 , and gcd ( 2 , 5 ) = 1 \text{gcd}(2,5) = 1 , ϕ ( 5 ) = ϕ ( 5 1 ) = 5 ( 1 1 5 ) = 4 \phi(5) = \phi(5^1) = 5 \left ( 1 - \frac {1}{5} \right ) = 4

Denote D = 2 2 2 2 2 2 six 2’s \LARGE D = \underbrace{2^{2^{2^{2^{2^2}}}}}_{\text{six 2's}} ,

D m o d 4 = 0 D \bmod 4 = 0 , and by Fermat's Little Theorem

D m o d 5 = 2 2 2 2 2 2 m o d 4 m o d 5 = 1 D \bmod 5 = 2^{2^{2^{2^{2^2}}} \bmod 4 } \bmod 5 = 1

D D satisfy the linear congruences:

x 1 0 ( m o d 4 ) x_1 \equiv 0 \pmod {4}

x 1 1 ( m o d 5 ) x_1 \equiv 1 \pmod {5}

By Chinese Remainder Theorem D m o d 20 = 16 D \bmod 20 = 16 , consider modulo 25 25

Then C 2 16 ( 2 4 ) 4 ( 16 ) 4 ( 9 ) 4 11 C \equiv 2^{16} \equiv (2^4)^4 \equiv (16)^4 \equiv (-9)^4 \equiv 11

Again, C C satisfy the linear congruences:

x 2 0 ( m o d 4 ) x 2 11 ( m o d 25 ) \begin{aligned} x_2 & \equiv & 0 \pmod {4} \\ x_2 & \equiv & 11 \pmod {25} \\ \end{aligned}

By Chinese Remainder Theorem C m o d 100 = 36 C \bmod 100 = 36

So by considering modulo 125 125

B 2 36 ( 2 7 ) 5 2 3 5 2 7 2 14 111 B \equiv 2^{36} \equiv (2^7)^5 \cdot 2 \equiv 3^5 \cdot 2 \equiv -7 \cdot 2 \equiv -14 \equiv 111

One last time, B B satisfy the linear congruences:

x 3 0 ( m o d 8 ) x 3 111 ( m o d 125 ) \begin{aligned} x_3 & \equiv & 0 \pmod {8} \\ x_3 & \equiv & 111 \pmod {125} \\ \end{aligned}

By Chinese Remainder Theorem B m o d 1000 = 736 B \bmod {1000} = 736

Hence,

( A ( 4 , 5 ) + 3 ) m o d 1000 = 736 A ( 4 , 5 ) m o d 1000 = 733 \begin{aligned} \left ( A(4,5) + 3 \right ) \bmod{1000} & = & 736 \\ A(4,5) \bmod{1000} & = & \boxed{733} \\ \end{aligned}

Note: Using the same logic, the last three digits of A ( 4 , n ) A(4,n) is 733 733 for n = 2 , 3 , 4 , n=2,3,4, \ldots

r u human ?!!! ;)

Aakarshit Uppal - 7 years, 3 months ago
Nilesh Sah
Feb 17, 2014

The solution to this is quite simple... Looking at the function one can certainly say that its a question pertaining to a recursive function algorithm. But the answer A(4,5) is so large that it overflows the memory even for a long long int (in C++). But since the question only talks about finding the 3 digits only, just a little tweak of adding a mod 1000 for n+1 will work it out.. :D

So here's the code (in C++)

#include <iostream>
#include <conio.h>
using namespace std;

int x = 4, y = 2;

long long int A(int m, int n) {
if( m == 0 )
    return (n+1)%1000;
else if( m > 0 && n == 0 )
     return A(m-1, 1);
else if( m > 0 && n > 0 )
     return A( m-1, A(m,n-1) );
}

int main() {
cout << A(4,5);
getch();
}

I wrote exactly same code but didn't work. (The IDE just closed without even showing any error) . I think you did this on a super computer because A(4,5) would still be calculated and then last 3 digits would be printed. Kindly help if i am wrong.

Aakarshit Uppal - 7 years, 3 months ago
Sam Leo
Mar 14, 2014

I used DP memoization for this, combined with the fact that you only need the last 3 digits.. Ran in seconds. Programming language was in JavaScript.

var A=[[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]];
function a(m,n){
   if(A[m][n])return A[m][n]; 
   if(!m) return A[m][n] = n+1; 
   if(n==0 && m>0) return A[m][n] = a(m-1,1)%1000; 
   if(m>0 && n>0) return A[m][n] = a(m-1,a(m,n-1))%1000;
}
Joe Sixpack
Mar 1, 2014

Let tower(n) denote a tower of n 2s. Some easy inductions give A(4,n) = tower(n+3) - 3.

Obviously tower(5) = 0 mod 8. But 2 8 = 16 = 2 16 2^8 = 16 = 2^{16} mod 20, so 2 8 n = 16 2^{8n} = 16 mod 20 for any n and hence tower(6) = 16 mod 20.

Similarly, 2 16 = 36 = 2 16 + 20 2^{16} = 36 = 2^{16+20} mod 100, hence tower(7) = 36 mod 100.

Finally, 2 36 = 736 = 2 136 2^{36} = 736 = 2^{136} mod 1000, so tower(8) = 736 mod 1000 and hence A(4,5) has last three digits 733.

Robin Kumar
Feb 19, 2014

Since we are required to print last three digits only we should pass last 3 digits only in every recursive call. The following JAVA code illustrates my idea.

public class Ackerman {

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    System.out.println(new Ackerman().A(4, 5));
}

int A(int m, int n) {
    if (m == 0)
        return n + 1;
    else if (m > 0 && n == 0)
        return A((m - 1) % 1000, 1); // n%1000 will give last three digits
    else
        return A((m - 1) % 1000, A(m % 1000, (n - 1) % 1000));
}

}

Why doesn't this work in c++? (The IDE just closed without even showing any error) .

Aakarshit Uppal - 7 years, 3 months ago

there must be some problem with your code. Try to find some thing u may have missed.

Robin Kumar - 7 years, 3 months ago

Here's my code :-

 #include<iostream.h>
 #include<conio.h>
 double A(double m,double n);
 void main()
 {
 double a, b, c;
 cin>>a>>b;
 c=A(a,b);
 cout<<"Answer "<<c;
 getch();
 }

 double A(double m,double n)
 {
 if (m==0) 
 return (n+1);

 else if ((m>0) && (n==0))
 return (A((m-1)%1000,1));

 else if ((m>0) && (n>0))
 {
 double d=A(m%1000,(n-1)%1000);
 return (A(((m-1)%1000),d));
  }

 else cout<<"Oooops!!";
 }

Aakarshit Uppal - 7 years, 3 months ago

@Aakarshit Uppal my code gave the correct output on a laptop ... no super computer is needed for this question if your algorithm is correct . As i told you already there were many problems with your C++ code. I'm mentioning some of them: ->> % operator should be used with integers not with floating point numbers(double in your case). ->> using namespace std was missing the above two problems will result in compilation error. I don't know how you did not get one.

Anyways i have corrected your code . Do have a look at it, Provide the inputs from console(4 5) and keep calm for 5-10 secs you will get the output for sure(After all its not a supercomputer right?? :D ). Hope its clear. Code:- // replace hash with # symbol. I did it because of formatting issues

hash include <iostream>

hash include <conio.h>

using namespace std;

int A(int m, int n);

void main() {

int a, b, c;
    cin >> a >> b;
    c = A(a, b);
cout << "Answer " << c;

}

int A(int m, int n) { if (m == 0) return (n + 1);

else if ((m > 0) && (n == 0))
    return (A((m - 1) % 1000, 1));

else if ((m > 0) && (n > 0))
    return A((m - 1) % 1000, A(m % 1000, (n - 1) % 1000));
else
    cout << "Oooops!!";

}

Robin Kumar - 7 years, 3 months ago

0 pending reports

×

Problem Loading...

Note Loading...

Set Loading...