Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternative implementation of Ackermann function in C

I wrote a program in C which calculates the Ackermann values for 2 non-negative integers entered by the user. The program checks if the integers are non-negative and if they are it calculates the Ackermann value of them and then asks for new input or exit. The program works fine in C and I have no problem with it. Here is my code:

int ackermann(int m, int n){
        if (m == 0) return n + 1;
        if (n == 0) return ackermann(m - 1, 1);
        return ackermann(m - 1, ackermann(m, n - 1));
}

BUT, in fact, for the needs of a university lesson we use a modified version of C(basically the same but with some different syntax rules) which simulates the syntax and the rules of MIPS Assembly language. More specifically, we use registers to manipulate all the data except from arrays and structs. Also, we cannot use for, while, or do-while loops and we use if and goto statements instead. So I wrote the following program in this language(as I said it is no more than C with different syntax). My problem is that it works only for (x,0) and (0,y) user inputs(x and y are non-negative numbers). It doesn't work for (4,1), (3,2) and generally all inputs that have no zero. I understand that it cannot work efficiently for very large numbers like (10,10) due to the vast stack of these calculations. But I want it to work for some simple inputs like Ackermann(3,1) == 13. For more on Ackermann function please see this: http://en.wikipedia.org/wiki/Ackermann_function Here is my code:

//Registers --- The basic difference from C is that we use registers to manipulate data
int R0=0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,R15,R16,R17,R18,R19,R20,R21,
R22,R23,R24,R25,R26,R27,R28,R29,R30,R31;

int ackermann(int m, int n){

    R4 = m;
    R5 = n;

    if(R4 != 0)
        goto outer_else;
    R6 = R5 + 1;
    return R6;

    outer_else:
        if(R5 != 0)
            goto inner_else;
        R7 = R4 - 1;
        R6 = ackermann(R7, 1);
        return R6;

        inner_else:
            R8 = R5 - 1;
            R9 = ackermann(R4, R8);
            R10 = R4 - 1;
            R6 = ackermann(R10, R9);
            return R6;
}
like image 234
mgus Avatar asked Dec 07 '12 15:12

mgus


1 Answers

I think your problem is that those register values are defined as global variables and they're being updated by an inner call to ackermann(), while an outer call depends on those values not changing. For example, take a look at the inner_else clause in your register version of ackermann(): it calls ackermann(R4, R8), and in the next statement depends on the current value of R4 but the recursive call alters the setting of R4 before it reaches the assignment statement.

Two common solutions:

  1. Define your registers as local variables and let the compiler keep track of per function call state for you.

  2. On entry to your ackermann() function, manually save the state of all registers and then restore same on exit.

Although solution 1 is easier, I suspect your teacher might prefer solution 2, because it illustrates the kind of technique used by a compiler to deal with actual register management in its generated assembly code.

like image 64
Marc Cohen Avatar answered Sep 21 '22 00:09

Marc Cohen