| n+1 if m = 0
ACK(m,n) =| ACK(m-1,1) if m>0 and n = 0
| ACK(m-1, Ack(n-1)) otherwise
where 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.