Pow() function and converting double to byte/int

As you may know Pow() return Double, it cause a strange problem when i need to convert the number to BYTE

There is the code that i used

byte temp;
for(i=0;i<8;i++)
  {
   temp = pow(2,i);
   Serial.println(temp,DEC);
  }

and this is the output

1

2

3
 // should be 4
7
 // should be 8
15
 // should be 16
31
 // should be 32
63
 // should be 64
127
 // should be 128

Is there any solution for it?

Using pow to operate on integer arguments is wrong. The pow() function was not designed for that.

Raising 2 to the nth power is a simple bit shift operation:

temp = 1 << n;

with n = 0 being a special case (temp = 0).

Thanks, I just wonder what would be faster your method or this one? (I need this part to be executed as fast as passible)

byte base2(int e)
{
  switch(e)
  {
  case 0: return B00000001;
  case 1: return B00000010;
  case 2: return B00000100;
  case 3: return B00001000;
  case 4: return B00010000;
  case 5: return B00100000;
  case 6: return B01000000;
  case 7: return B10000000;
  }
}

Thanks, I just wonder what would be faster your method or this one? (I need this part to be executed as fast as passible)

Quit wondering. Test and see.

Use micros to record a start time. Call your function 10,000 times with different values. Use micors to record an end time. Compute the difference.

Use micros to record a start time. Call the bit shift method 10,000 times with different values. Use micors to record an end time. Compute the difference.

See for yourself which is faster.

The overhead of a function call, required in your method, will far outweigh the need to not calculate a value.

Of course, an array lookup could be even faster.

byte pows[] = {0, 2, 4, 8, 16, 32, 64, 128};

byte val = pows[6]; // will get 2^6.

Well, it look obvious now that the array method is the faster

By the way 2^0=1 not 0

Well, it look obvious now that the array method is the faster

but only when tested you see the real difference :

unsigned long start, stop;

byte pows[] = { 
  1, 2, 4, 8, 16, 32, 64, 128};

byte x;


void setup()
{
  Serial.begin(115200);
}

void loop()
{  
  Serial.println("Start");

  start = micros();
  for(int i=0; i< 10000; i++)
  {
    x = i%8;
  }
  stop = micros();
  Serial.print("REF : ");
  Serial.println(stop - start);

  start = micros();
  for(int i=0; i< 10000; i++)
  {
    x = 1 << (i%8);
  }
  stop = micros();
  Serial.print("SHIFT : ");
  Serial.println(stop - start);


  start = micros();
  for(int i=0; i< 10000; i++)
  {
    x = pows[i%8];
  }
  stop = micros();
  Serial.print("ARRAY : ");
  Serial.println(stop - start); 


  start = micros();
  for(int i=0; i< 10000; i++)
  {
    x = base2(i%8);
  }
  stop = micros();
  Serial.print("FUNC  : ");
  Serial.println(stop - start);


  start = micros();
  for(int i=0; i< 10000; i++)
  {
    switch(i%8)
    {
    case 0: 
      x =  B00000001;
    case 1: 
      x =  B00000010;
    case 2: 
      x =  B00000100;
    case 3: 
      x =  B00001000;
    case 4: 
      x =  B00010000;
    case 5: 
      x =  B00100000;
    case 6: 
      x =  B01000000;
    case 7: 
      x =  B10000000;
    }
    // int y = x;
  }
  stop = micros();
  Serial.print("SWITCH: ");
  Serial.println(stop - start);

  start = micros();
  for(int i=0; i< 10000; i++)
  {
    x = pow(2, i%8);
  }
  stop = micros();
  Serial.print("POW: ");
  Serial.println(stop - start);  

  Serial.println("Done");
  Serial.println();
}



byte base2(int e)
{
  switch(e)
  {
  case 0: 
    return B00000001;
  case 1: 
    return B00000010;
  case 2: 
    return B00000100;
  case 3: 
    return B00001000;
  case 4: 
    return B00010000;
  case 5: 
    return B00100000;
  case 6: 
    return B01000000;
  case 7: 
    return B10000000;
  }
}

run and be amazed :slight_smile:

for the really fanatics → change the signature of the function to ==> byte base2(int e) and run again

Just a note for the original code: pow(2,3) gave you 7 because the result was 'almost' 8 (for example 7.99999999...) and the integer conversion just lopped off the fraction. That explains the other ones as well, and is important to know if you mix integers and floating point.

As for speed, the array solution is about as fast as you can get without special code (that is code that for your specific solution). Compared to floating point, it is a huge deal faster; since the Arduino has no floating point chip, all floating point math math is done in code, using a great deal of instructions, and making it best to avoid until you really need floating point.

@robtillaart There are some things about the test that are not fair. In the switch case, there is no use of the value that is computed in the switch case, so the whole switch statement gets optimized away. Uncommenting the int y = x; statement has no affect, since y is never used, so it, too, gets optimized away. Adding volatile in front of int on that statement, to prevent optimizing the whole block of code away results in the switch statement taking considerably longer.

Thanks Paul for these additions and insights

The y=x line was added to prevent optimization but they where not needed

Another bug is that the switch statement is missing break; at every case. therefor it can be optimized .... // copied code without thinking :blush:

Rob