Go Down

Topic: which is more efficient? using -> or . to access array of struct members (Read 12587 times) previous topic - next topic

doughboy


did some  "integer sin " exploarations here - http://forum.arduino.cc/index.php?topic=69723.0 -
might be useful

@doughboy
Can you tell more about the goal and how your code looks like (post it) . Probably we can help optimizing.



interesting. actually, if I use sin, it will be simpler, since this is for 8 bit pwm, I only work with values up to 255. I can divide the cycle into 360 resolution (1 degree can be as low as 2ms, since pwm freq is 490hz), and as high as 28ms.

the formula is (using degrees instead of radians). since isin does the %360, I can pass in the 16bit parameter as is.
value = 128 + 127 * isin(degree);
value is unsigned 8 bit

do you see a way to optimize your function for this usage?  perhaps return as signed integer (-255 to 255) without dividing by 255, and do the /255 outside the function to make it truly floating point free? or as in earlier discussion, will the compiler  optimize the code into all integer operation?


doughboy

come to think of it, I can probably just map the whole function into a table, and maybe lower the resolution down to 255 or even 128 from 360. That will be a 255 (or 128) byte lookup table though.

robtillaart

something like this?
Code: [Select]
uint8_t isinTable8[] = {
  0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44,
  49, 53, 57, 62, 66, 70, 75, 79, 83, 87,
  91, 96, 100, 104, 108, 112, 116, 120, 124, 128,

  131, 135, 139, 143, 146, 150, 153, 157, 160, 164,
  167, 171, 174, 177, 180, 183, 186, 190, 192, 195,
  198, 201, 204, 206, 209, 211, 214, 216, 219, 221,

  223, 225, 227, 229, 231, 233, 235, 236, 238, 240,
  241, 243, 244, 245, 246, 247, 248, 249, 250, 251,
  252, 253, 253, 254, 254, 254, 255, 255, 255, 255,
  };

int isin(long x)
{
  boolean pos = true;  // positive - keeps an eye on the sign.
  if (x < 0)
  {
    x = -x;
    pos = !pos; 
  } 
  if (x >= 360) x %= 360;   
  if (x > 180)
  {
    x -= 180;
    pos = !pos;
  }
  if (x > 90) x = 180 - x;
   if (pos) return isinTable8[x]/2 ;
  return -isinTable8[x]/2 ;
}

returns a val between -127and 127
Rob Tillaart

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

joshuabardwell


come to think of it, I can probably just map the whole function into a table, and maybe lower the resolution down to 255 or even 128 from 360. That will be a 255 (or 128) byte lookup table though.


Be careful. Depending on which Arduino board you are using, tables like this can quickly run you out of SRAM. I had two 100-byte lookup tables once, and then I decided to increase the resolution to 256-bytes each, and my program started crashing because it was running out of SRAM. You might want to look into using the progmem() keyword and its associated functions if you are working on a board with not much SRAM (Uno, for example) and have many large tables.

nickgammon

You can put the table into PROGMEM at the cost of one more clock cycle to access an element.

Meanwhile some of you guys might want to edit your posts on page 1 and use code tags. The posts that jump into italics half-way through are a clue you are referring to [i] in them.

Not only is the italics distracting, the code makes no sense when the [i] disappears.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

doughboy



come to think of it, I can probably just map the whole function into a table, and maybe lower the resolution down to 255 or even 128 from 360. That will be a 255 (or 128) byte lookup table though.


Be careful. Depending on which Arduino board you are using, tables like this can quickly run you out of SRAM. I had two 100-byte lookup tables once, and then I decided to increase the resolution to 256-bytes each, and my program started crashing because it was running out of SRAM. You might want to look into using the progmem() keyword and its associated functions if you are working on a board with not much SRAM (Uno, for example) and have many large tables.


That's  right. I figured I actually only need a resolution of  30, so I actually only need a 30 byte array. I'm using a mega and currently have over 3k free ram.

BTW, do you remember how much time a call to the arduino sin function take?

joshuabardwell


BTW, do you remember how much time a call to the arduino sin function take?


Not only do I not remember, I never knew!

doughboy



BTW, do you remember how much time a call to the arduino sin function take?


Not only do I not remember, I never knew!


Sorry, that question was meant for Rob, and he mentions this right away in his link.

Today I did some investigations in a lookup function for sin(x).  Sin(x) takes approx 120 micros and I wanted more speed, and I knew the price was precision.


robtillaart

simple speed test for the above isin()
result 13.52 micros per call on average. Normal sin(x) is 120 micros so factor 9 by keeping it integer.

You can gain a bit more by making the parameter int instead of long
AND remove the 360 test ==> results in 10.51 micros per call (11x faster) on my UNO.
Code: [Select]
//
//
//    FILE: isinSpeedTest.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE:
//    DATE: 2013-11-03
//     URL:
//
// Released to the public domain
//

uint8_t isinTable8[] = {
  0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44,
  49, 53, 57, 62, 66, 70, 75, 79, 83, 87,
  91, 96, 100, 104, 108, 112, 116, 120, 124, 128,

  131, 135, 139, 143, 146, 150, 153, 157, 160, 164,
  167, 171, 174, 177, 180, 183, 186, 190, 192, 195,
  198, 201, 204, 206, 209, 211, 214, 216, 219, 221,

  223, 225, 227, 229, 231, 233, 235, 236, 238, 240,
  241, 243, 244, 245, 246, 247, 248, 249, 250, 251,
  252, 253, 253, 254, 254, 254, 255, 255, 255, 255,
};

int isin(long x)
{
  boolean pos = true;  // positive - keeps an eye on the sign.
  if (x < 0)
  {
    x = -x;
    pos = !pos; 
  } 
  if (x >= 360) x %= 360;   
  if (x > 180)
  {
    x -= 180;
    pos = !pos;
  }
  if (x > 90) x = 180 - x;
  if (pos) return isinTable8[x]/2 ;
  return -isinTable8[x]/2 ;
}
volatile uint8_t x = 0;


void setup()
{
  Serial.begin(115200);
  Serial.println("Start ");

  uint32_t start = micros();
  for (int i=0; i<360; i++)
  {
    x = isin(i);
  }
  uint32_t diff = micros() - start;
  Serial.println(diff/360.0);

  for (int i=0; i<360; i++)
  {
    if (i%10 ==0) Serial.println();
    Serial.print(isin(i));
    Serial.print('\t');
  }
  Serial.println("\n...done...");
}

void loop() {}
Rob Tillaart

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

robtillaart

just saw some real kick!
+ param int iso long
+ 1 set of ()
+ do math 8 bit asap
==>  3.58 micros ==> 30+ faster

It can even be faster:
+ restricting the input to 0..360 
==> 2.86 micros()  ==> 42 times faster!! (of course  42;)

Code: [Select]
//
//    FILE: isinSpeedTest.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE:
//    DATE: 2013-11-03
//     URL:
//
// Released to the public domain
//

uint8_t isinTable8[] = {
  0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44,
  49, 53, 57, 62, 66, 70, 75, 79, 83, 87,
  91, 96, 100, 104, 108, 112, 116, 120, 124, 128,

  131, 135, 139, 143, 146, 150, 153, 157, 160, 164,
  167, 171, 174, 177, 180, 183, 186, 190, 192, 195,
  198, 201, 204, 206, 209, 211, 214, 216, 219, 221,

  223, 225, 227, 229, 231, 233, 235, 236, 238, 240,
  241, 243, 244, 245, 246, 247, 248, 249, 250, 251,
  252, 253, 253, 254, 254, 254, 255, 255, 255, 255,
};

int isin(int x)
{
  boolean pos = true;  // positive - keeps an eye on the sign.
  uint8_t idx;
  // remove next 6 lines for fastestl!
   if (x < 0)
    {
      x = -x;
      pos = !pos; 
    } 
   if (x >= 360) x %= 360;   
  if (x > 180)
  {
    idx = x - 180;
    pos = !pos;
  }
  else idx = x;
  if (idx > 90) idx = 180 - idx;
  if (pos) return isinTable8[idx]/2 ;
  return -(isinTable8[idx]/2);
}
volatile uint8_t x = 0;


void setup()
{
  Serial.begin(115200);
  Serial.println("Start ");

  uint32_t start = micros();
  for (int i=0; i<360; i++)
  {
    x = isin(i);
  }
  uint32_t diff = micros() - start;
  Serial.println(diff/360.0);

  for (int i=0; i<360; i++)
  {
    if (i%10 ==0) Serial.println();
    Serial.print(isin(i));
    Serial.print('\t');
  }
  Serial.println("\n...done...");
}

void loop() {}
Rob Tillaart

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

doughboy

since we are speaking of optimization, are you able to check and confirm the compiler did not turn your for loop into a noop?

when I did the object dump check on some of my test program, I noticed the compiler completely omits code that actually are noop, like assigning something to a variable that is never used.

robtillaart


since we are speaking of optimization, are you able to check and confirm the compiler did not turn your for loop into a noop?

when I did the object dump check on some of my test program, I noticed the compiler completely omits code that actually are noop, like assigning something to a variable that is never used.

I made X volatile to prevent optimization of the compiler..
commenting out the  x=isin(i) line gave a time of 0.01 :)

to do a more accurate speed test I should run the test with one and with two calls in the loop, and then subtract the results.
(that would subtract the loop overhead)
Rob Tillaart

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

doughboy


robtillaart

Welcome,
you can squeeze out a bit more by not doing the /2 in code but by doing it in the table.
so the table goes from 0..127
Rob Tillaart

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

doughboy


Welcome,
you can squeeze out a bit more by not doing the /2 in code but by doing it in the table.
so the table goes from 0..127


while we are on this topic, let's split hair that is already split.
I've read the /2 is faster than >>1.
is that correct?

Go Up