I have a program that is tracking cycles of an industrial machine. I need to re-calculate the average after every cycle. Not hard math, however, as cycles add up, the average gets further and further out of whack (Excel or a calculator has a result of 19.52 and my Xojo code has 19.56). At some point, my code stops calculating the average. I do not have error handling skills in Xojo despite reading the documentation multiple times so forgive me if I’m doing it wrong. Below is my code. The commented lines is the first way I tried it. Both have the same issue. Any idea what I’m missing?
Thanks in advance!
CalcAve(ElapsedSecs as Double, CurrentAve as Double, CycleCount as Double) As Double
Dim NewCalcAve As Double
Try
If CycleCount < 1 Then
'NewCalcAve = (Round(ElapsedSecs*100))/100
NewCalcAve = ElapsedSecs
else
'NewCalcAve = (Round((ElapsedSecs + (CurrentAve * CycleCount)) / (CycleCount + 1)*100))/100
NewCalcAve = (ElapsedSecs + (CurrentAve * CycleCount)) / (CycleCount + 1)
End If
NewCalcAve = CDbl(Format(NewCalcAve, "#.00"))
WriteLog(Str(NewCalcAve), Str(ElapsedSecs))
Catch e As IOException
MsgBox("File IO Error DA1: " + e.Reason)
End Try
Return NewCalcAve
Interesting. Cheers Norman.
Moral: don’t do the math in your head…
Nonetheless, where I was going was : is multiplying the rolling average by the countsofar a recognised way of doing this?
The Round() or the CDbl(Format(NewCalcAve, “#.00”)) might lead to a progressive variance as anything beyond 2 dp is being lost on each pass.
My mental arithmetic is definitely not up to proving if that loss is enough to account for it.
I suppose IF you had unlimited precision numerics then computing the “sum so far” as the current average * count so far should be ok but IANAM (I am not a mathematician) and could not prove this if required
However, I have used this technique before and have not run into significant errors
That said, applying round, ceil, or other functions like that, may most certainly affect the result
From what I can see Dawn is using much the same algorithm I’m suggesting
Algebraically it should work as Norman stated. But this section on Doug’s code will little by little cause his equation to diverge.
NewCalcAve = CDbl(Format(NewCalcAve, "#.00"))
WriteLog(Str(NewCalcAve), Str(ElapsedSecs))
He should either create another variable for displaying and not touch the variable the calculations are running on, or just format the display w/o changing the variable.
I was trying to avoid adding all the cycles as the count can climb quickly. I will change my approach and keep a running sum to see if the variance clears up. Thanks all!
I haven’t tried this, but I think if you make the following change you should get what you are expecting (within the numerical precision of the variables being used).
change
NewCalcAve = CDbl(Format(NewCalcAve, "#.00"))
WriteLog(Str(NewCalcAve), Str(ElapsedSecs))
to:
[quote=446537:@Norman Palardy]I think, in general the average is,
( ( * ) + ) / [/quote]
That depends on what count we are talking about.
Your algorithm is from the point of view of the original count:
( ( prevAvg * prev# ) + newVal ) / prev# + 1
or as prevAvg * prev# = previous Sum
and
prev# + 1 = new#
(previous sum + new value ) / new#
But I suspect the problem is in the cycleCount that is fed in as a parameter - that Dawns uses that algorithm from the point of view of the NEW count as AFTER the count the new average is calculated. So the cycle count would be off in the calculation.
The original code was solid. It’s just that the inherent inaccuracy in a Double representation causes the result to drift over time. As Norman said, with unlimited precision, it would yield the correct result. A Double doesn’t have that kind of precision.
That isnt in question and is thoroughly beside the point.
We dont know that this is the issue. And I simply offered an alternative possibility: If a method is called with wrong parameters then you get wrong results. Dismissing other possible error sources seems unwise at this stage.
So unless Dawn supplies a few hard numbers we cant check and determine where in her app the problem is.
The code algorithm is good indeed, but the truncation Dawn is doing after the algorithm will cause errors way before any Double limitation. This following line is messing up the whole algorithm:
NewCalcAve = CDbl(Format(NewCalcAve, "#.00"))
One should never alter the variable the algorithm is using for display purposes.
[quote=446743:@LangueR]The code algorithm is good indeed, but the truncation Dawn is doing after the algorithm will cause errors way before any Double limitation. This following line is messing up the whole algorithm:
NewCalcAve = CDbl(Format(NewCalcAve, "#.00"))
One should never alter the variable the algorithm is using for display purposes.[/quote]