Go Down

### Topic: Pow() function and converting double to byte/int (Read 2096 times)previous topic - next topic

#### kirill578

##### Jul 10, 2011, 04:39 pm
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]
`123 // should be 47 // should be 815 // should be 1631 // should be 3263 // should be 64127 // should be 128`

Is there any solution for it?

#### PaulS

#1
##### Jul 10, 2011, 04:58 pm
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

#2
##### Jul 10, 2011, 05:08 pm
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

#3
##### Jul 10, 2011, 05:18 pm
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

#4
##### Jul 10, 2011, 06:04 pm
Well, it look obvious now that the array method is the faster

By the way 2^0=1 not 0

#### robtillaart

#5
##### Jul 10, 2011, 07:22 pm
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)

#### Utopia

#6
##### Jul 11, 2011, 06:59 pm
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

#7
##### Jul 11, 2011, 07:22 pm
@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

#8
##### Jul 12, 2011, 11:46 am
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

Rob
Rob Tillaart

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

Go Up