Read these instructions carefully. For this assignment, you will modify an assembly language subroutine to perform multiple precision addition more efficiently. Your new subroutine will be used in a program that computes large Fibonacci numbers.
We can represent multiple precision integers with arrays of normal integers. Each integer in the array would represent part of the multiple precision integer, just as each digit in a decimal number represents part of the number. But rather than doing arithmetic in base 10, as we do with decimal numbers, we do arithmetic in base 232 for multiple precision integers.
int A[] = { 0x12345678, 0xabcdef01, 0x87654321 };represents the hexadecimal value 0x87654321abcdef0112345678 as an array of size 3. For this assignments, all arrays will be of size 10, but you can imagine extending this representation to arrays of varying sizes.
#define N 10 /* add multiple-precision integers in arrays A and B, placing result into * multiple-precision integer in array C. each array is of size 10. * returns 1 if there is a carry (i.e. overflow), 0 otherwise */ int add (unsigned int A[], unsigned int B[], unsigned int C[]) { int i, carry; unsigned int c; /* initially, carry is zero */ carry = 0; /* go through each element from least to most significant */ for (i=0; i<N; i++) { /* add the i'th elements of A and B with the carry */ c = A[i] + B[i] + carry; /* there is a carry out of c, i.e. c overflowed, if * either operand is greater than the sum */ carry = (A[i] > c) || (B[i] > c); /* place the partial sum into the i'th element of C */ C[i] = c; } /* return carry (i.e. unsigned overflow) */ return carry; }This code is a nice general algorithm in terms of the #defined constant N which we can change to support higher precision numbers. But if we are only interested in 320-bit numbers (i.e. 10 32 bit integers) then we can unroll the for loop, producing the following C code:
int add (unsigned int A[], unsigned int B[], unsigned int C[]) { int carry; unsigned int c; carry = 0; c = A[0] + B[0] + carry; carry = (A[0] > c) || (B[0] > c); C[0] = c; c = A[1] + B[1] + carry; carry = (A[1] > c) || (B[1] > c); C[1] = c; c = A[2] + B[2] + carry; carry = (A[2] > c) || (B[2] > c); C[2] = c; c = A[3] + B[3] + carry; carry = (A[3] > c) || (B[3] > c); C[3] = c; c = A[4] + B[4] + carry; carry = (A[4] > c) || (B[4] > c); C[4] = c; c = A[5] + B[5] + carry; carry = (A[5] > c) || (B[5] > c); C[5] = c; c = A[6] + B[6] + carry; carry = (A[6] > c) || (B[6] > c); C[6] = c; c = A[7] + B[7] + carry; carry = (A[7] > c) || (B[7] > c); C[7] = c; c = A[8] + B[8] + carry; carry = (A[8] > c) || (B[8] > c); C[8] = c; c = A[9] + B[9] + carry; carry = (A[9] > c) || (B[9] > c); C[9] = c; return carry; }Here, the loop letting i go from 0 through 9 has been replaced by 10 identical copies of the loop body. This will enable the code to avoid the loop overhead and work faster, at the cost of making the function less general since it now only works for 320-bit numbers.
Click here to see the assembly code produced by gcc -O3 -S for this unrolled version of add. Unfortunately, this code is not as efficient as it could be, even though the compiler tried its best. In particular, the compiler does not realize that it can use the carry flag (CF) to represent the carry variable and the "add with carry longword" (adcl) instruction to add the elements of A and B.
Compile the program using both the old add subroutine and your new improved add subroutine:
gcc -O3 -o fib.old fib.c add-unrolled.s gcc -O3 -o fib.new fib.c add-adcl.SAs a test, try listing the first 400 Fibonacci numbers by invoking each program:
./fib.old 400 ./fib.new 400Each program should produce exactly the same output. By the way, the 400th Fibonacci number is hexadecimal is this:
17322a2cfd320a23266116c4c2c95b3feea3e57fa3d9dfe8b8591e1d72120f26c6fadbIf your program doesn't produce that number when you use your version of the add function, then your add function is incorrect. (Note that you do not have to turn in anything related to Fibonacci numbers, but your assignment will be graded in terms of the fib.c program so make sure you use it to test your code.)