Fibonacci Sequence - value's range

I always like to write my own little programs when i'm trying to understand how something works.
I have been trying to understand how we can send data from one function to the other, so i tried to create a little sketch with prints out the Fibonacci sequence. The numbers are calculated in one place and then sent to another function which will print them.

Here is the code i am using:

/*

 Just a little simple sketch to try to understand how to send values
 from one function to another.
 
 ...and maybe understand a little bit better te Fibonacci Sequence!
 
 
     Circuit:
     button to Arduino Pin4 (with pull-up resistor)
 
 
 April 2014    Luis Pato
 
 */

// VARIABLES
const int button = 4;                  // button Pin
int buttonState;                       // will hold the current state of button
int lastButtonState = HIGH;            // will store the previous state of button

unsigned long a = 1;                   // variables used to calculate the Fib. numbers
unsigned long b = 1;
unsigned long c;


void setup() {
  pinMode(button,INPUT);               // set button as input
  Serial.begin(9600);                  // begin serial communication
  delay(2000);                         // 2s delay, so we can start the Serial Monitor
  intro();                             // print the "intro info"
}  


void loop() {
  buttonState = digitalRead(button);   // read the button state

                                       // if button is just pressed
  if(buttonState == LOW && buttonState != lastButtonState){
    c = a + b;                         // calculate next Fib. number
    printNumbers(a,b,c);               // send F[n-2], F[n-1] and F[n] to the print function
    a = b;                             // update F[n-2]
    b = c;                             // update F[n-1]
  }
  lastButtonState = buttonState;       // store last button state
}


void printNumbers(int d, int e, int f){
  // this funcion is used to print the Fib. numbers into a "table" on the Serial Monitor                          
  Serial.print(d);                     // print F[n-2]
  Serial.print("\t");
  Serial.print("+");                   
  Serial.print("\t");
  Serial.print(e);                     // print F[n-1]
  Serial.print("\t");
  Serial.print("=");
  Serial.print("\t");
  Serial.println(f);                   // print F[n], the new Fib. number
}


void intro() {
  // this function prints some intro info about the Fibonacci Sequence
  Serial.println("The Fibonacci Sequence works by adding a number to its preceding number in the sequence");
  Serial.println(" ");
  Serial.print("F[n-2]");
  Serial.print("\t");
  Serial.print("\t");
  Serial.print("F[n-1]");
  Serial.print("\t");
  Serial.print("\t");
  Serial.print("F[n]");
  Serial.println();
  for (int i=0; i<5; i++){             // print the first 5 numbers in the sequence
    delay(250);
    c = a + b;
    printNumbers(a,b,c);
    a = b;
    b = c;
  }
  Serial.println(" ");
  Serial.println("Click the button to find out the next number in the sequence...");
  Serial.println(" ");
}

and here is the output:

but, as you can see, when we get to the:
17711 + 28657 =
instead of getting 46368 we get -19168

why is this happening?
Is it something wrong with my "formula"? are the values rolling over? Is Mr. Fibonacci playing a joke on me?

:wink:

why is this happening?

Integers are 16bit on the Arduino with on bit reserved for the sign in the signed version, so 32767 is the highest number such a variable is able to hold, afterwards it overflows and goes negative. If you want to play with higher numbers, use the long version or better the explicit types: int32_t.

As pylon states it's an int problem.

This functions parameters...

void printNumbers(int d, int e, int f){

don't match the variable type passed

unsigned long a = 1;                   // variables used to calculate the Fib. numbers
unsigned long b = 1;
unsigned long c;

so the 32 bit unsigned number is being truncated to a 16 bit signed number type.

pylon:

why is this happening?

Integers are 16bit on the Arduino with on bit reserved for the sign in the signed version,

Please don't confuse "integer" with the "int" datatype.
"long" is an integer, as is "char".

There is no "reserved" sign bit (that would be a "sign-and-magnitude" format, which has representations for both +ve and -ve zero and a symmetrical number range) in two's complement the sign bit is part of the number.

ah, of course, it makes sense. i was using int on the printing function...
Thanks guys!

another question...
you mention "int32_t". What are these?
I was looking for it here in the Arduino Reference but i can't find it. i can find int, unsigned int, long,... but no int32_t. googling it also doesn't turn out anything really cool.
Any link to a good place were i could read about it?
=)

you mention "int32_t". What are these?

I cannot provide you a reference page, but it's quite easy. These types just represent integers and unsigned integers with a clearly defined bit length and number range. For Arduino, they are defined in hardware/tools/avr/lib/avr/include/stdint.h. You have int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t and uint64_t. The digits in the types correspond to the bit length types have.

Ah, cool, didn't know that.

So int16_t would be a 16 bit int and a uint32_t would be a unsigned 32 bit int?

But what would be the difference between using an uint32_t or an unsigned int? When we we use one or the other?

But what would be the difference between using an uint32_t or an unsigned int?

On an AVR Arduino, an "int" (signed or unsigned) is sixteen bits.

On an AVR Arduino, an "int" (signed or unsigned) is sixteen bits.

Exactly and on Linux it's 32 bits. If you use "int" your code is not portable and you always have to think about how much bits your variable have now. If you use explicit types it's clear and portable.

pylon:
If you use "int" your code is not portable...

Not portable? So i cannot run it on other systems? But if i am writing a sketch just for the Arduino then it would be ok, right? Or if i want the data to be sent to another system (maybe even through serial) that it makes a difference?

So, using something like a uint16_t will not only define the type if variable, but will also define how many bits of memory it will take.
On the other hand, using an int is only defining the variable type, which happens to have a maximum value, but which could also take less space.
Is this right?

Could someone give me an example of when this would be useful / necessary on an Arduino sketch?
=)

boguz:
So, using something like a uint16_t will not only define the type if variable, but will also define how many bits of memory it will take.
On the other hand, using an int is only defining the variable type, which happens to have a maximum value, but which could also take less space.
Is this right?

Nearly. Both int and uint16_t will reserve some memory for the veriable. The difference is that in the latter case it is clearer for a developer how many space is used. For your Arduino project it is interchangeable and you can just stick to using int, long and so on.

The advantage you gain is that you can easily see/remember how many space is occupied by the variable. This might be helpful if you open the code in one year or so.

boguz:
Could someone give me an example of when this would be useful / necessary on an Arduino sketch?
=)

From the reference page here...

Integers are your primary data-type for number storage.

On the Arduino Uno (and other ATMega based boards) an int stores a 16-bit (2-byte) value. This yields a range of -32,768 to 32,767 (minimum value of -2^15 and a maximum value of (2^15) - 1).
On the Arduino Due, an int stores a 32-bit (4-byte) value. This yields a range of -2,147,483,648 to 2,147,483,647 (minimum value of -2^31 and a maximum value of (2^31) - 1).

If you write a sketch for the DUO using int (or long) then it may not behave the same if used on an UNO as the datatype is half the number of bits and may cause overflow.

boguz:

pylon:
If you use "int" your code is not portable...

Not portable? So i cannot run it on other systems?

Maybe not as-is. You do know that system to system is not always the same?
Or even compiler to compiler on the same system or the same hardware with different OS may differ?

With good technique you can put the major differences up front but nothing is everywhere perfect.
It is part of the job of porting to know the hardware and systems and take care of differences.

But if i am writing a sketch just for the Arduino then it would be ok, right?

Now it's silly laugh time! Arduino covers 8 pin, 8-bit ATtiny's to 32-bit ARM and Pentium based controllers.

What I write for an UNO, the by-far most common Arduino board I know of, will probably run on a MEGA or Leonardo or most AVR-based Arduinos, compatibles and stand-alone AVR chips with minor changes mostly to pin numbers that I try to keep defined at the top of the sketch. And that ain't bad.
The more vanilla the sketch, the more portable. The more chip specific, the less portable.
I can't run a sketch that needs 6k RAM on an UNO without a lot of change if at all.

Or if i want the data to be sent to another system (maybe even through serial) that it makes a difference?

If you send the data as text or BCD then it will make far less difference. The receiving system still needs to be able to handle the data.

You want to crank out Fibonacci sequence?
The every value will be >= 0.
Unsigned integers will let you work to twice that maximum of signed numbers.

You want BIG values? Then you use the big unsigned integers, the 64-bit unsigned long long.
And you make sure that any constants you use are cast to the same type.

Yes, plain AVR Arduinos can use 64-bit signed or unsigned integer variables.
Type unsigned long long is good to 18446744073709551615 == 0xFFFFFFFFFFFFFFFF.
It can hold 19 decimal places all 0 to 9 and still a 1 on top.

But that is FAR from the end. You can use text or BCD (binary coded decimal, 8 bits makes 2 digits) to work to "arbitrary precision", ie as many places as you have memory/storage and ingenuity to get. There's even libraries for some of those methods.

Yes, plain AVR Arduinos can use 64-bit signed or unsigned integer variables.

...but can't print 'em :frowning:

AWOL:

Yes, plain AVR Arduinos can use 64-bit signed or unsigned integer variables.

...but can't print 'em :frowning:

Not using Serial.print( myULL ).

add these to print.cpp + signatures in print.h and you should be able to print 64 bits (unsigned) longs (slowly)

size_t Print::println(int64_t number, int base)
{
    size_t n = 0;
    n += print(number, base);
    n += println();
    return n;
}

size_t Print::print(int64_t number, int base)
{
    size_t n = 0;
    if (number < 0)
    {
        write('-');
        number = -number;
        n++;
    }
    n += print((uint64_t)number, base);
    return n;
}

size_t Print::println(uint64_t number, int base)
{
    size_t n = 0;
    n += print((uint64_t)number, base);
    n += println();
    return n;
}

size_t Print::print(uint64_t number, int base)
{
    size_t n = 0;
    unsigned char buf[64];
    uint8_t i = 0;

    if (number == 0)
    {
        n += print((char)'0');
        return n;
    }

    if (base < 2) base = 2;
    else if (base > 16) base = 16;

    while (number > 0)
    {
        uint64_t q = number/base;
        buf[i++] = number - q*base;
        number = q;
    }

    for (; i > 0; i--)
    n += write((char) (buf[i - 1] < 10 ?
    '0' + buf[i - 1] :
    'A' + buf[i - 1] - 10));

    return n;
}