Pages: [1]   Go Down
Author Topic: Pow() function and converting double to byte/int  (Read 1010 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
byte temp;
for(i=0;i<8;i++)
  {
   temp = pow(2,i);
   Serial.println(temp,DEC);
  }

and this is the output

Code:
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?


Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 615
Posts: 49420
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 615
Posts: 49420
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
byte pows[] = {0, 2, 4, 8, 16, 32, 64, 128};

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

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

By the way 2^0=1 not 0
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 217
Posts: 13739
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

but only when tested you see the real difference :

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

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

Rob Tillaart

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

Victoria, BC, Canada
Offline Offline
Full Member
***
Karma: 0
Posts: 222
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 615
Posts: 49420
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 217
Posts: 13739
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Rob Tillaart

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

Pages: [1]   Go Up
Jump to: