pow function (math) behaving unexpectedly

Hello guys 'n' gals,

Here's a little thingie to make you wonder (at least it made me wonder a lot!).
Check out this simple bit of code:

void setup() {
  Serial.begin(9600);

  byte i;
  int bla;
  
  for (i=0; i<4; ++i) {
    bla = pow(2,i);
    Serial.println(bla);
  }
}

void loop() {
}

Run it... i'm curious what results you will get. On my Arduino (Diecimila) I get this:

1
1
3
7

Where I would expect:

1
2
4
8

??????

If I change the basenumber ("2" in the example) to 3 or 4.... the results make sense!
(1,3,9,27) resp (1,4,16,64)

What am I doing wrong????

BTW, what I'm trying to accomplish is this: I have 4 buttons in a row, and I want to my function to return the decimal number that corresponds with the binary number that would be formed by the pressed and unpressed buttons, like this:
(some parts borrowed from examples on this site)

/*
 * RobotKit - v0.2
 */
 
#define DEBOUNCE 20 

 
void setup() {
  byte i;

  // set up serial port
  Serial.begin(115200);

  // set up pins communicating with switches as input
  for (byte i = 2; i <= 5; ++i) {
    pinMode(i, INPUT);
  }
}

void loop() {
  static byte previous[8];
  static long time[8];
  byte reading;
  byte index;
  int selected = 0;

  for (index = 0; index < 4; ++index) {
    reading = digitalRead(index + 2);
    if (reading == LOW && previous[index] == HIGH && millis() - time[index] > DEBOUNCE)
    {
      // switch pressed
      time[index] = millis();
      selected += pow(2, index);
    }
    previous[index] = reading;
  }
  Serial.print("result = ");
  Serial.println(selected);
  delay(500);
}

Is it a bug?? I see a few examples on this forum which are using the pow function, also with basenumber 2, and they seem to cause zero problems.
Help! Please! :-/

Best regards,
Geert Jan

Oh hello to myself!

Dear Vidioterie,

Haven't been able to figure out the (buggy?) behaviour of the pow function, but did find another solution, which is more hardcore even ;). Here it is:

Declare this function at the top of your program:

#define SET(x,y) (x|=(1<<y))

And voila, you can set the bits of your BYTE variable, which you can then Serial.println(variable, DEC).

Probably it could be even more hardcore to use the PORTB/PINB (for example) and do some bitshifting, but hell...this works great already!

Cheers,
moi

Hello, Geert,

The problem with your code example stems from the fact that pow is a floating-point function, and floating-point arithmetic is never completely accurate. My guess is that pow(2, 2) is returning something like 3.999997. Because C++ converts double to int by simply truncating, when you assign the result of pow to your int variable bla, you get the surprising result of 3 instead of 4.

But as you discovered, if you are simply tracking the state of 4 buttons, it is much easier, not to mention more efficient and accurate, to use bits within a byte and avoid the expensive call to pow altogether.

mh

Hello Mikal,

Aha, that surely sheds some light on the matter. Thanks for your explanation. Still it leaves me wondering though, because: if I replace the reference to index by a hardcoded number (i.e. 2 or 3), without changing any other part of the code, the result is what it should be (resp. 4 and 8), even though the same truncating would occur...?

Anyway, I've been able to solve this whole issue with the approach mentioned above, using the SET(x,y) function.

Now all I have to do is wait for my WaveShield to arrive..... exciting! :o

Cheers,
GJ

The compiler tries to recognize calculations on constants at compile time and substitute the constant results ( resp. 4 and 8 in your example ) and not bother to call the floating point function, so it s not truncated.

EDIT: cut out a whole description of the same problem, the search engine had only given methe first post, not the explenation as to why it happens. Thanks for the feedback, now i can solve my problem as well.