Surrender to the Overflow

It’s a common question beginning programmers ask: “Why use different types of variables when every number can be expressed as a float?”

The answer is, “efficiency.” It’s the same reason you write 1 instead of 1.000000 when you do math. A “1” is more compact, just as an integer occupies less space and is easier for the processor to manipulate than a real number.

Back when storage space and processor speed were limited, real number calculations became a true burden on the computer. Early CPUs lacked math instructions, so a separate co-processor was required. And storage was tight, so if you could get by with a short int value, you declared a variable as such.

Today’s processors have advanced math instructions built-in, plus the computer has oodles of RAM. Still, it’s wise to use a float or double only when a fractional or large value is required. And with integer sizes, a long holds more values than an short, but it’s more efficient to use a short when long-size values aren’t required. The only problem you run into is when values overflow.

As an example, the following code generates a Fibonacci sequence. It’s related to Exercise 9-16 in Beginning Programming with C For Dummies. The LIMIT value sets the length of the Fibonacci sequence:

#include <stdio.h>

#define LIMIT 10000

int main()
{
    int fibo,nacci,count;

    fibo=0;
    nacci=1;
    count=0;

    do
    {
        printf("%d\n",fibo);
        fibo+=nacci;
        printf("%d\n",nacci);
        nacci+=fibo;
        count+=2;
    } while( count < LIMIT );

    return(0);
}

When run, you see 10000 numbers in a Fibonacci sequence. On my terminal window, I see the sequence start like this:

0
1
1
2
3
5
8

And on and on, until the end, which looks like this:

1640003618
-913691081
726312537
-187378544
538933993
351555449
890489442

These are not values in a Fibonacci sequence. In fact, this output is the telltale sign of overflow: The program is running fine, but the variable width is unable to hold the huge value calculated. So the numbers are crazy, with negative values followed by positive values.

To fix overflow, you must set the proper variable size. The range for an int variable on my computer is between -2,147,483,648 and 2,147,483,647. So the first change is to declare fibo and nacci as unsigned int values and modify printf() to use the %u (unsigned int) placeholder. The maximum value stored in an unsigned int is 4,294,967,295. Is that big enough?

Here is the last part of the program’s output:

1640003618
3381276215
726312537
4107588752
538933993
351555449
890489442

No, overflow is still occurring.

The next step is to change the int type to long, but I’ll leapfrog that option and go straight to the unsigned long long variable type, which stores a range of values from zero to 18,446,744,073,709,551,615.

The %llu placeholder is used in the printf() function to display unsigned long long integer values.

After modifying the code, I ran it again. Here is the output’s tail:

3889924131843504162
223230997310352951
4113155129153857113
4336386126464210064
8449541255618067177
12785927382082277241
2788724563990792802

Again, I don’t see a good sequence, which means that the long long int variable isn’t wide enough to hold the 10,000th value in a Fibonacci sequence.

At this, point I surrender to floating point variables, which removes accuracy but might yield correct values. Variables fibo and nacci are declared as double, and the printf() placeholder %E is used for exponential notation. Here’s the last part of the output:

INF
INF
INF
INF
INF
INF
INF

Oh, well. Apparently the 10,000th value in the Fibonacci sequence is INF or infinity. It’s a number so huge that standard programming variables can’t hold it.

I scrolled back to see the last legitimate value and it was 1.306989E+308, which is huge and not very accurate.

The point of this lesson isn’t to discover the 10,000th Fibonacci sequence value, but rather to demonstrate when it’s necessary to switch from int to float variables and the consequences of doing so.

Leave a Reply