asm_book/section_3/precomputation/README.md
2024-04-13 14:24:55 -05:00

2.8 KiB

Section 3 - Pre-computation

Time versus space.

This is the essential battle that programmers face. In order to go faster, more memory is used. In order to economize on memory, more computation is needed.

This duality is demonstrated in no better way than comparing a calculated method (economizing space at the expense of time) versus an entirely precomputed method (sacrificing space to reduce time).

In this section, we will demonstrate three methods of calculating factorials from 0 to 15.

  • Iteratively

  • Recursively

  • By pre-computation

Certainly, for the purposes of this demonstration, it is not necessary to implement both iterative and recursive methods. We do so for fun and for any lessons the reader can glean.

C Driver

Here, you will find a version written in C. We will repurpose main() to drive versions in assembly language.

Iterative

long Iterative(long n) {
    long retval = 1;
    for (long i = 1; i <= n; i++) {
        retval *= i;
    }
    return retval;
}

First, notice that this algorithm's work increases linearly with the parameter n. Therefore this algorithm is O(n).

We translated this function into assembly language to produce the code provided below. This code is condensed. To see the original code with comments, please see here.

ifact:
        mov         x2, x0
        mov         x0, 1       // equivalent to retval = 1
        mov         x1, 1       // equivalent to i = 1

        // This has five instructions (20 bytes) in the inner loop which
        // increases in work by O(n).

10:     cmp         x1, x2
        bgt         99f
        mul         x0, x0, x1
        add         x1, x1, 1
        b           10b

99: 
        ret

Reminder, the above code is condense. You will note that the code that performs the calculation is 5 instructions (or 20 bytes) long. This isn't much but again, the algorithm runs in O(n) time.

Recursive

long Recursive(long n) {
    long retval;
    if (n <= 1)
        retval = 1;
    else
        retval = n * Recursive(n - 1);
        
    return retval;
}

The code below is condensed. The original code, with comments, can be found here.

rfact:
        PUSH_P      x29, x30
        mov         x29, sp

        cmp         x0, 1
        bgt         10f
        mov         x0, 1       // ensure x0 is 1 - it could be less.
        b           99f

10:     // If we get here, n must be more then 1. Recursion is needed.

        PUSH_R      x0          // save the current n
        sub         x0, x0, 1   // prepare for recursion
        bl          rfact       // 
        POP_R       x1          // restore the current n
        mul         x0, x0, x1  // multiply it by recursive return

99:     POP_P       x29, x30
        ret