This is what I use:
//calculate exponentially smoothed moving average
int ma0(int sample) {
static int sum=0, avg=0; //sum and avg
sum+=(sample-avg); //update sum
avg=sum/MA_WGT; //calculate the moving average
return avg;
}
MA_WGT is the same as your DENOM. ALPHA is set to 1.
It should be much faster than yours. And you may be able to prove mathematically that they are the same.
First, yes, mathematically they are the same. And in fact, if you pass in ALPHA=1 the compiler correctly eliminates it entirely.
However, yours probably is /not/ faster -- not that it matters on something so minimalist.
The salient difference between implementations is that you store the sum and avg and I only store the sum. Storing the sum saves you a calculation on each iteration (a shift), but it costs you an extra load and store.
I put your code into a class and compiled it with gcc-arm -Os -fno-inline -S to see what comes and they were just as you'd expect:
Mine:
.fnstart
.LFB15:
ldr r3, [r0]
lsr r2, r3, #6
sub r3, r3, r2
add r1, r3, r1
str r1, [r0]
@ sp needed
lsr r0, r1, #6
bx lr
Yours:
dannyf_ema_c<long, long, 1ul, 64ul>::update(long):
.fnstart
.LFB16:
ldr r3, [r0]
ldr r2, [r0, #4]
sub r3, r3, r2
add r1, r3, r1
str r1, [r0]
lsr r1, r1, #6
str r1, [r0, #4]
@ sp needed
mov r0, r1
bx lr
If you allow inlining, I suspect yours might do a bit better because the compiler might be able to leave sum/avg in registers.