I'm having trouble with a loop that is supposed to add together a number of very small float values to eventually produce a weighted average, like so:
for(int k = 0; k < slopes.size(); k++){
if(slopes.get(k).isClimbing() == false){
float tempWeight = (slopes.get(k).getzDiff() / highestFallZ);
weight += tempWeight;
highestFallX += (slopes.get(k).getEndX() * tempWeight);
}
highestFallX = highestFallX / weight;
}
Essentially what it does is produce a weighting from one attribute of an object (the result of which is always between 0 and 1), then modifies another attribute of the same object by that weighting and adds the result to a running tally, which is in the end divided by the sum of the weightings. All values and variables are of the type float.
Now the problem I'm running into is that within just a few steps the running tally (highestFallX) is growing exponentially into -infinity. I've run some diagonistics, and they've shown that each individual value added was in the range between -1 and -1*10^-5 (after the multiplication with the weighting) and no more than 60 of them were added together, so neither overflow nor underflow should be a problem. For comparison, here is a list of the last value added (LastFallX) and the tally (HighestFallX) during the first few steps of the loop:
LastFallX: -1.2650555E-4
HighestFallX: -1.2650555E-4
LastFallX: -6.3799386E-4
HighestFallX: -0.25996128
LastFallX: -4.602447E-4
HighestFallX: -87.01444
LastFallX: -0.0020183846
HighestFallX: -16370.462
LastFallX: -4.158747E-5
HighestFallX: -826683.3
From there on it keeps growing exponentially, and hits -infinity within about 10 more loops. The highestFallX variable isn't referenced nor modified by anything else during this loop.
One way of expressing an average is:
totalValue += nextValue * nextWeight;
totalWeight += nextWeight;
average = totalValue / totalWeight;
This is prone to overflow in totalValue
, as you have seen.
Instead you can also do:
totalWeight += nextWeight;
average += ((nextValue * nextWeight) - average) / totalWeight;
In your case, I think that might look like:
for(int k = 0; k < slopes.size(); k++){
if(slopes.get(k).isClimbing() == false){
float tempWeight = (slopes.get(k).getzDiff() / highestFallZ);
weight += tempWeight;
float weightedValue = (slopes.get(k).getEndX() * tempWeight);
float delta = weightedValue - highestFallX;
highestFallX += delta / weight;
}
}
but I'm still trying to work out exactly how your weighted average should work, so I'm a little unsure of that last bit.