| n+1 if m = 0 ACK(m,n) =| ACK(m-1,1) if m>0 and n = 0 | ACK(m-1, Ack(n-1)) otherwisewhere both m and n are non-negative.
For this exercise we will write a program which will compute values for Ackermann's function for 0≤ m ≤ 3 and 0 ≤ n ≤ 4. If you look at the article on wikipedia, you will see why this limit was chosen.
A first step would be to write the c++ code to compute this table:
#include <iostream> #include <iomanip> using namespace std; int Ack(int m, int n); const int M_LIMIT = 3; const int N_LIMIT = 4; int main() { int m,n; cout << "m\\n"; for(n=0;n<= N_LIMIT; n++) { cout << setw(4) << n; } cout << endl; for(m=0; m<= M_LIMIT; m++) { cout << setw(4) << m; for(n=0;n<= N_LIMIT; n++) { cout << setw(4) << Ack(m,n); } cout << endl; } return 0; } int Ack(int m, int n) { if (m == 0) { return n+1; } else if (n == 0) { return Ack(m-1,1); } else { return Ack(m-1, Ack(m,n-1)); } }This code is available here
We do quite a bit of cout << setw(4) << val so I want to write a function to do this, sort of.
.data ... space: .asciiz " " ... CoutWithWidth4: # input: a0 holds the number to print # # assume that the number is between 0 and 9999 # We will overwrite a0, but we can store a0 in t0 since we are not making a call move $t0, $a0 li $v0,4 la $a0, space bgt $t0, 999, NoSpace bgt $t0, 99, OneSpace bgt $t0 9, TwoSpace syscall TwoSpace: syscall OneSpace: syscall NoSpace: syscall move $a0, $t0 li $v0, 1 syscall jr $ra
The next task is to write the main program.
.data M_LIMIT: .word 3 N_LIMIT: .word 4 label: .asciiz " m\\n" endl: .asciiz "\n" space: .asciiz " " .text main: # int m, n I will use $s0 for m, and $t0 for n. # this means I need to save $t0 before all calls and # restore it afterwords. # set up a space to save $t* used in computation addi $sp, $sp, -4 # cout <<"m\\n" li $v0,4 la $a0, label syscall # for (n=0; n<= N_LIMIT; n++) move $t0, $zero lw $s1, N_LIMIT MainLoop1Start: bgt $t0, $s1, MainLoop1End # cout << setw(4) << n move $a0, $t0 sw $t0, 0($sp) jal CoutWithWidth4 lw $t0, 0($sp) addi $t0, $t0, 1 b MainLoop1Start MainLoop1End: # } # cout << endl; la $a0, endl li $v0, 4 syscall # for(m=0;m<M_LIMIT;m++) { move $s0, $zero lw $s2, M_LIMIT OuterLoopStart: bgt $s0, $s2, OuterLoopOut # cout << setw(4) << m move $a0, $s0 jal CoutWithWidth4 # for(n=0;n<N_LIMIT;n++) move $t0, $zero InnerLoopStart: bgt $t0, $s1, InnerLoopOut move $a0, $s0 move $a1, $t0 sw $t0,0($sp) jal ACK jal CoutWithWidth4 lw $t0, 0($sp) addi $t0, $t0, 1 b InnerLoopStart InnerLoopOut: # cout << endl; la $a0, endl li $v0, 4 syscall addi $s0, $s0, 1 b OuterLoopStart OuterLoopOut: mainEnd: # restore the stack pointer addi $sp, $sp, 4 li $v0, 10 syscall CoutWithWidth4: # input: a0 holds the number to print # # assume that the number is between 0 and 9999 # We will overwrite a0, but we can store a0 in t0 since we are not making a call move $t0, $a0 li $v0,4 la $a0, space bgt $t0, 999, NoSpace bgt $t0, 99, OneSpace bgt $t0 9, TwoSpace syscall TwoSpace: syscall OneSpace: syscall NoSpace: syscall move $a0, $t0 li $v0, 1 syscall jr $ra ACK: li $a0, 999 jr $ra
sw $fp, -4($sp) addi $fp, $sp, -4 sw $ra, -4($fp) sw $a0, -8($fp) addi $sp, $fp, -8
lw $ra, -4($fp) addi $sp, $fp, 4 lw $fp, -4($sp) jr $ra
beq $a0, $zero, case1 # if m =0, just return n+1 beq $a1, $zero, case2 # m is positive, so check to see if n=0
case1: # return n-1 addi $a0, $a1, 1 b ACKEnd
case2: # return Ack(m-1, 1) addi $a0, $a0, -1 li $a1, 1 jal ACK ACKEnd:
# find Ack(m,n-1) addi $a1, $a1, -1 jal ACK
# now compute Ack(m-1, Ack(m,n-1)) # the return value (Ack(m,n-1)) is in $a0, move it to $a1 move $a1, $a0 # get m back from the activation record lw $a0, -8($fp) # and subtract 1 from it addi $a0, $a0, -1 jal ACK b ACKEnd
If you are completely confused or totally lazy, this file might be helpful.