-
Notifications
You must be signed in to change notification settings - Fork 5
Description
This method looks like a misguided attempt to have the integer division round to nearest rather than round towards zero. It involves both a 32-bit division and a 32-bit modulo operation, both of which are very expensive on AVR. Furthermore, it is used with a multiplier of 10, which is arbitrary and does not guarantee correct rounding in all circumstances. Edit: it does guarantee correct rounding as long as the multiplier is even.
A simpler and cheaper method is to add half the denominator before the division, i.e. replace p/q with (p+q/2)/q. Note that, if q is unsigned, q/2 is optimized by the compiler into a bit shift, which is extremely cheap. For example, in the computation of the mean, the scaling factor can be removed and the lines:
long mean = sum / _values.available();
mean = _longRound(mean, 10);
return(mean);can then be replaced with:
return (sum + _values.available() / 2) / _values.available();The same applies to the median.
The standard deviation is more tricky, as it uses not only an integer division but also a float to long conversion, both of which involve rounding. The easiest solution is to carry the division in floating point and add 0.5 before converting to long, i.e. remove the scaling and replace:
long stDev = sqrt(sum / denominator);
stDev = _longRound(stDev, 10); // round and undo that multiplier of 10
return(stDev); with:
return sqrt((float) sum / denominator) + 0.5;