multiplication/division question

would multiplying by 0.1 be quicker than dividing by 10?

ive read that arduino is something like 20 times faster at multiplying than dividing.

thanks in advance!

Do a test & see. Use micros() for timing them.

it seems to take twice as long to multiply by 0.1 instead of dividing by 10 but i think the reason is that it returns a float.

do you have any ideas for optimizing the following line of code?

float tempC = (val[pin][0] + val[pin][1] + val[pin][2] + val[pin][3] + val[pin][4] + val[pin][5] + val[pin][6] + val[pin][7] + val[pin][8] + val[pin][9]) / 10;

it just occurred to me to use a uint16_t instead of a float, since all values will be positive and the function that line of code is in is an int anyway.

replace the division with an integer multiply shift operation (and maybe use a loop)

uint16_t tempC = 0;
for (int i=0; i< 9; i++)  tempC += val[pin][i];
tempC = (tempC *205) /2048;  //power of 2

divide by power of 2 are subtractions of the exponent of the float so relative fast

volatile float x = 100;
volatile float y = 0;
volatile float a = 0;

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

  Serial.println("\n");

  uint32_t start = micros();
  for (int i=0; i<1000; i++)
  {
    a = x/10;
  }
  uint32_t stop = micros();
  Serial.println(stop - start);
  Serial.println(y);

  start = micros();
  for (int i=0; i<1000; i++)
  {
    a = (x*205)/2048;  // divide by power 2
  }
  stop = micros();
  Serial.println(stop - start);
  Serial.println(y);
}

void loop() {}

approx 30% faster

whoa! cool, thanks!

So youre saying its quicker to multiply by 205 then divide by 2048 because 2048 is a binary number?

sort of like just slicing off the last digit?

vulture2600:
whoa! cool, thanks!

So youre saying its quicker to multiply by 205 then divide by 2048 because 2048 is a binary number?

no because 2048 is a power of 2 and that the IEEE754 float has its exponent as a power of 2
so dividing by 2048 means subtracting 11 from exponent, which is much faster than a real division.
Of course time is also used by the multiplication *205

Note that this trick only works for a certain range of values.
Because it is temperature the sum of 10 temps will probably not exceed 1000.

vulture2600:
it seems to take twice as long to multiply by 0.1 instead of dividing by 10 but i think the reason is that it returns a float.

do you have any ideas for optimizing the following line of code?

float tempC = (val[pin][0] + val[pin][1] + val[pin][2] + val[pin][3] + val[pin][4] + val[pin][5] + val[pin][6] + val[pin][7] + val[pin][8] + val[pin][9]) / 10;

When you need speed you can always do something like this (example convert degrees C to degrees F):

Regular way (slow): F = (C * 1.8) + 32;

Decimal way (faster): F = ((C * 18) / 10) + 32;

Optimize Celsius Fahrenheit - I've been there - Celsius to Fahrenheit revisited - integer averaging considered harmful - Libraries - Arduino Forum - :slight_smile:

Because it is temperature the sum of 10 temps will probably not exceed 1000.

In this case it will very much add up to more than 1000 because I'm adding up analog reading values, not temperatures. After I've averaged them, THEN I convert to Celsius:

/* getTemp(): each time the function is called, a new reading is taken and stored to the 3x10 matrix. each row is then averaged and
returned as temp for each sensor. AREF = 2.04V.
*/
int getTemp(uint8_t pin) {
  val[pin][reading] = analogRead(pin); 
  delay(20); //delay between each analog pin is needed to reduce cross interferance between readings.
  uint16_t tempC = 0;
  for (uint8_t i = 0; i <= 9; i++) { //adds up all the values in the row.
    tempC += val[pin][i];
  }
  tempC = (tempC * 205) / 2048; //clever way to divide by 10 to average them quickly.
  tempC = map(tempC, 50, 882, -40, 125); //convert analog reading to celsius.
  if (celsius) {
    return tempC;
  } //end if.
  else {
    return (9.0 / 5.0) * tempC + 32;
  } // end else.
} //end getTemp().

I havent uploaded these changes to the Arduino yet, so I dont know if it will matter. Your thoughts?

Krupski:
Regular way (slow): F = (C * 1.8) + 32;

Decimal way (faster): F = ((C * 18) / 10) + 32;

Decimal way (faster, with better rounding): F = ((C * 18 + 5) / 10) + 32 ;

Or using shifts to lose a multiply: F = ((C + (C<<3)) + 2) / 5 + 32 ;

Or converting to tenths of a deg F, thereby losing less accuracy and
making the calculation faster: Ftenths = (C << 1) + (C << 4) + 320 ;

(that's really just avoiding the divide by ten issue until you need to display it,
and Serial.print is so slow anyway that you won't care!)

I did some quick and dirty math.

On average, the analog readings of the sensors are in the 3-400 range. If, for example, it was 500, that would mean added up they would be 5000. Then multiplying by 205 would put me over 1 million, which is way out side the uint16_t range of ~65k. However, I'm immediately dividing by 2048 to put me right back where I started.

Does it matter that the value as high as a million is never stored to a variable before being divided back down to a savable value?

Ex:

uint16_t tempC = 0;
  for (uint8_t i = 0; i <= 9; i++) { 
    tempC += val[pin][i];
  }
  tempC = (tempC * 205)

Should I change uint16_t to a uint32_t?

you could try

tempC = (tempC * 205L) >> 2048;  <<<< WRONG

the L after 205 makes the math 32 bit. and the assignment makes it 16 bit again.

update :

tempC = (tempC * 205L) >>  11;
or
tempC = (tempC * 205L) / 2048;

Awesome, thanks!

Its a whole other thread, but I have no understanding of ">>". They're bit level commands, correct?

yes it is a shift operator shifting all bits n positions.
a shift of 1 == a division by 2 for integers

I don't think you want to shift by 2048 positions. 8^)

Don't you mean 11 here?

KeithRB:
I don't think you want to shift by 2048 positions. 8^)

Don't you mean 11 here?

My mistake, :blush: :blush: :blush:
updated the code in the post above

(tempC * 205L ) >> 2048 does NOT work! :slight_smile:

Thanks for clarifying!