0

I was reading this Wikipedia article, and attempting to implement a 'map' based solution in C, where a 'map' is just an int array, initialized to 0.

For some reason it works up to fib(93), then starts outputting strange numbers. If it matter's I'm specifying -std=c99:

#include <stdio.h>
#include <stdlib.h>

// represents a fib num
typedef unsigned long long fib_t;

// the default value of our 'map'
const int FIB_NULL   = 0;

// could get from input, set here for now
const int FIB_MAX    = 100;

// our 'map' for fib nums
static fib_t *fibMap;

// calculate the fib num n
fib_t fib( unsigned int n )
{
    // if this num, n, is not 0 or 1, and is FIB_NULL, then calculate it
    if( n > 1 && FIB_NULL == fibMap[n] )
    {
        fibMap[n] = fib( n-1 ) + fib( n-2 );
    }

    // get it from the map
    return fibMap[n];
}

// used to setup the 'map' for the fibs
static void initFibMap()
{
    // emulate a map
    fibMap = malloc( sizeof(fib_t) * FIB_MAX);

    // initialize it to 'null'
    memset(fibMap, FIB_NULL, sizeof(fib_t) * FIB_MAX);

    // by definition
    fibMap[0] = 0;
    fibMap[1] = 1;
}

int main(int argc, char *argv[]) 
{
    // setup our 'map'
    initFibMap();

    for( unsigned int i=0; i<FIB_MAX; i++ )
    {
        // breaks on 94
        printf("Fib #%d: %llu\n",i, fib(i));
    }
}

Strange output:

// . . .
// . . .
// Fib #90: 2880067194370816120  // good
// Fib #91: 4660046610375530309  // good
// Fib #92: 7540113804746346429  // good
// Fib #93: 12200160415121876738 // good
// Fib #94: 1293530146158671551  // WHAT?
// Fib #95: 13493690561280548289
// Fib #96: 14787220707439219840
// Fib #97: 9834167195010216513
// Fib #98: 6174643828739884737
// Fib #99: 16008811023750101250
Josh
  • 11,980
  • 9
  • 70
  • 116
  • 4
    You *do* realize that you're overflowing even an `unsigned long long right`? – Mysticial Sep 13 '12 at 19:20
  • @Mystical: I had not, I've never worked with numbers this large before. A quick trip to `limit.h #ULONG_MAX` reveals that you're indeed correct. Any recommendations on getting around this issue? – Josh Sep 13 '12 at 19:22
  • 2
    Unfortunately, C doesn't have native support for bignums. So you'll either need to write your own or use a library such as GMP. If you're willing to sacrifice precision, going to floating-point might be acceptable. – Mysticial Sep 13 '12 at 19:24
  • 2
    @Josh you can use some big number support library - for example, GNU bigint. –  Sep 13 '12 at 19:24
  • @Mysticial: Thank you very much. I don't *need* any precision etc, this was just a learning exercise. But I'll keep that in mind for the future. – Josh Sep 13 '12 at 19:26
  • @H2CO3: Thanks, I'll keep that in mind if I ever need to use a large number outside of a learning exercise! – Josh Sep 13 '12 at 19:27
  • @Josh see my answer for that. :) –  Sep 13 '12 at 19:27

2 Answers2

2

With such large numbers, you're getting an unsigned integer overflow, which causes a "wrap around" to result in the original result of the operation, modulo 1 << bits, bits being the bit width of the particular integer type. If you want to represent these numbers, you have to use some kind of bignum library, such as the GNU GMP.

  • The behaviour of **unsigned** integers in computations that yield out-of-range results is completely defined by the standard, it's arithmetic modulo `2^WIDTH`. – Daniel Fischer Sep 13 '12 at 21:04
0

As number is getting large so integer is getting overflow so "wrap around" is happening so you can use either GNU GMP library or use string to represent numbers just like i did for factorial of large numbers link to http://codepad.org/bkWNV0JC

Anshul garg
  • 221
  • 2
  • 6