Home > Mobile >  Fibonacci sequence with 32 bit overflow algorithm
Fibonacci sequence with 32 bit overflow algorithm

Time:09-14

I am currently implementing a code that runs Fibonacci sequence (up to the 60th number) in riscv32I, which means that the memory address that I can use only has 32bits.

I have first implemented the code in C, and then in Assembly, but I am curious if the algorithm I used has a name so I can do more research. The code is as such,

#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint32_t n1 = 0;        // first pre number  (n - 2)
    uint32_t n2 = 1;        // second pre number (n - 1)
    uint32_t add = 0;       // current number

    uint32_t store_hi = 0;  
    uint32_t store_lo = 0; 
    uint32_t result;        // result
    uint32_t carry;         // carry bit

    for (int i = 2; i < 61; i  ) {
        carry = 0;                              // reset carry bit
        add = (uint32_t)(n2   n1);              // calculate current fib number
        
        if (add < n1) {                         // if overflow  
            carry = 1;                          // set carry bit
        }

        result = store_hi   store_lo;           // keeping track of higher bits
        result = result   carry;                // add carry bit

        store_lo = store_hi;                    // 
        n1 = n2;                                // update first pre number
        store_hi = result;                      // 
        n2 = add;                               // update second pre number
    }

    printf("Result32: 0x" PRIx32 " 0x" PRIx32 "\n", result, add);
    uint64_t result64 = ((uint64_t)result << 32) | add;
    printf("Result64: 0x6" PRIx64 " -> %" PRId64 "\n", result64, result64);
}

Running the code gives

Result32: 0x00000168 0x6c8312d0
Result64: 0x000001686c8312d0 -> 1548008755920

The basic concept is that because the Fibonacci number gets too big to fit within a single 32bit memory address, we have to split it into 32bit memory address, one holding the upper bit, and one holding the lower bit.

Let's generalize the above algorithm to a 4 bit memory space, to make it easier to follow the algorithm. This means that the maximum int can be 16. Let ss set n1 = 10, n2 = 10.

Loop 1:
     add = 4 # (10   10 = 20, but overflow, so 20 % 16 = 4)
     carry = 1
     result = 1
     store_lo = 0
     store_hi = 1
     n1 = 10
     n2 = 4
     # output: 0x14, 0x1 hi bit, 0x4 lo bit, which is 10   10 = 20
Loop 2:
     add = 14
     carry = 0
     result = 1
     store_lo = 1
     store_hi = 1
     n1 = 4
     n2 = 14
     # output: 0x1e, 0x1 hi bit, 0xe or 14, lo bit, which is 10   20 = 30
loop 3:
     add = 2 (14   4 = 18, but overflow, so 18 % 16, 2)
     carry = 1
     result = 3
     store_lo = 1
     store_hi = 2
     n1 = 14
     n2 = 2
     #output: 0x32, 0x3 hi bit, 0x2 low bit, which is  20   30 = 50
.... and so on.

This should work for any base, but I am curious what this algorithm is denoted as, or if it is simply related to modules and powers?

Thanks!

CodePudding user response:

It's called Arbitrary-precision arithmetic, you can read more about it here.

Arbitrary-precision arithmetic, also called bignum arithmetic, multiple-precision arithmetic, or sometimes infinite-precision arithmetic, indicates that calculations are performed on numbers whose digits of precision are limited only by the available memory of the host system.

CodePudding user response:

One of the troubles of venturing from 32-bit to 64-bit is that the now distant horizon rapidly becomes as constraining as the former, "closer" horizon was.

Below is a sketch of an "ASCII digit" Fibonacci calculator. Its two seeds are "0" and "1" at the right end of two 20 character buffers. (20 is arbitrary, but takes one beyond the 60th value in the Fibonacci sequence.) This could be optimised and improved in a hundred different ways. It is a "powers of ten" version that uses two ASCII strings for its storage. One could, if one was patient, use 1000 character buffer, or 10,000 to go deep into the Fibonacci realm...

I hope you find this interesting.

#include <stdio.h>

int main() {
    char f[2][20   1], *fmt = "%s   %-3d";
    int fn = 0;

    sprintf( f[0], " s", "0" );
    printf( fmt, f[ 0 ],   fn ); putchar( '\n' );
    sprintf( f[1], " s", "1" );
    printf( fmt, f[ 1 ],   fn );

    for( bool evod = false; getchar() != EOF;  evod = !evod ) {

        for( int carry = 0, i = 20; --i >= 0; ) {
            if( f[ evod][i] == ' ' && f[!evod][i] == ' ' && carry == 0 ) break;
            int f1 = f[ evod][i] == ' ' ? 0 : f[ evod][i] - '0';
            int f2 = f[!evod][i] == ' ' ? 0 : f[!evod][i] - '0';

            f1  = f2   carry; carry = f1 / 10; f[ evod][i] = f1   '0';
        }
        printf( fmt, f[ evod],   fn );
    }

    return 0;
}

Output

                   0   1
                   1   2
                   1   3
                   2   4
                   3   5
                   5   6
                   8   7
                  13   8
                  21   9
   /* omitted */
        591286729879   59
        956722026041   60
       1548008755920   61
       2504730781961   62
       4052739537881   63
  • Related