Go Down

Topic: Pow() function and converting double to byte/int (Read 1 time) previous topic - next topic

kirill578

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

Code: [Select]

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


and this is the output

Code: [Select]

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?



PaulS

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:
Code: [Select]
temp = 1 << n;
with n = 0 being a special case (temp = 0).

kirill578

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

Code: [Select]

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;
  }
}



PaulS

Quote
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.

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

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

kirill578

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

By the way 2^0=1 not 0

robtillaart

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


but only when tested you see the real difference :

Code: [Select]

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 :)

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

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

David Pankhurst

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.

PaulS

@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.

robtillaart

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  :smiley-red:

Rob
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up