pow()

Hi there!
I'm sorry to say I'm painfully new to all this arduino stuff and coding in general to be honest. Can anyone please explain these results to me? I'm pulling my hair out here!

int test[16];
void setup() {  
  for(int i = 0; i < 16; i++) {
    test[i] = pow(2,i);
  }
  Serial.begin(9600);
}
void loop() {
  for(int i=0;i<16;i++) {  
    Serial.print(test[i]);
    Serial.print(" ");
  }
}

the results I'm getting back are:

1, 2, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8192, 16383 and 32767.

The first 2 being right, the rest are low by 1 :frowning:

pow() takes and returns floats, you're sending and storing ints but not explicitly casting between the two. Maybe it's a type conversion problem?

Crikey, thanks! So obvious, really :smiley:

Funnily enough, it only gives the wrong answers if contained inside a For loop. For instance,

int test[16];

void setup() {
  
  test[0] = pow(2,0);
  test[1] = pow(2,1);
  test[2] = pow(2,2);
  test[3] = pow(2,3);
  test[4] = pow(2,4);
  ...etc
}
void loop() {
  for(int i=0; i<16; i++)
  {  
    Serial.print(test[i]);
  }
}

... is fine.

Hmm.

I've seen something like this before. Not on the Arduino (because I haven't tried it). It was years ago on PDPs, and the explanation has to do with the storage for floating point numbers. If you want to get into the depths of it, try reading up on hidden bit normalized. I haven't read the pertinent tech docs, so I don't know for a fact that the Atmel uses that, but it is an IEEE standard for floating point storage in binary. I'm not even going to claim, for sure, that this is the cause here, but it sure sounds like a good candidate.

I can only speculate that it works in the OP's example #2 because the parser is treating the numeric constants as floats, i.e. "2.0", "4.0". But I could be way off base there too.

Breakbeatkid - my guess it the compiler is trying to do some optimization in the loop and that's why it fails inside, but works standalone.

Justjed - I bet you're right.

thanks for the points folks, i'll keep trying some stuff out :slight_smile:

If you only need integer powers of two, you don't need to use "pow" at all.
An appropriately-sized variable and a shift operation are all that are needed.
e.g.

unisgned long twoToTheSixth = 1UL << 6;

Try this:

float test[16];
void setup() {  
  for(int i = 0; i < 16; i++) {
    test[i] = pow(2,i);
  }
  Serial.begin(115200);
}
void loop() {
  for(int i=0;i<16;i++) {  
    Serial.println(test[i]);
  }
  
  while (true) ;
}

I get:

1.00
2.00
4.00
8.00
16.00
32.00
64.00
128.00
256.00
512.00
1024.00
2048.00
4096.00
8192.00
16383.99
32767.98

Close enough, huh? Bear in mind that pow() is implemented using logs, which are approximate, and then multiplying by the number you first thought of.

As for why the int didn't work ... all I can say to that is: pfffft.

This has come up fairly recently and both your issues were addressed. The too small by one issue was caused by the pow function's use of floats so pow(2,2) gives 3.999 or similar, which when you cast it to int is 3. Add 0.5 before you cast to int.

The reason the explicit evaluations outside the loop work better is because the compiler can see that they are constants and evaluates them at compile time using its own pow calculation. As you can see, it does a better job.

Yeah, cheers! A bit of further digging and as was kindly pointed out I found some nice information in some other posts on this forum. In my defense I did have a look before I posted initially, but must've just missed this wonderful post http://arduino.cc/forum/index.php/topic,60701.0.html.

I used a custom Pow function of:

//2^i
unsigned int Pow(byte ex)
{
    return 1 << ex;
}

and it works perfectly!

Now to just figure out why my sketch works with a Serial to Midi converter, but not Moco for LUFA :frowning:

Thanks again. :slight_smile: