Repository: prometheus/prometheus
File: promql/functions.go (Go)

Code before:
				}
				_, err = mean.Add(toAdd)
				if err != nil {
					return mean, err
				}
			}
			return mean, nil
		})
		if err != nil {
			metricName := firstSeries.Metric.Get(labels.MetricName)
			if errors.Is(err, histogram.ErrHistogramsIncompatibleSchema) {
				return enh.Out, annotations.New().Add(annotations.NewMixedExponentialCustomHistogramsWarning(metricName, args[0].PositionRange()))
			} else if errors.Is(err, histogram.ErrHistogramsIncompatibleBounds) {
				return enh.Out, annotations.New().Add(annotations.NewIncompatibleCustomBucketsHistogramsWarning(metricName, args[0].PositionRange()))
			}
		}
		return vec, nil
	}
	return aggrOverTime(vals, enh, func(s Series) float64 {
		var (
			sum             = s.Floats[0].F
			mean, kahanC    float64
			incrementalMean bool
		)
		for i, f := range s.Floats[1:] {
			count := float64(i + 1)
			if !incrementalMean {
				newSum, newC := kahanSumInc(f.F, sum, kahanC)
				// Perform regular mean calculation as long as
				// the sum doesn't overflow.
				if !math.IsInf(newSum, 0) {
					sum, kahanC = newSum, newC
					continue
				}
				// Handle overflow by reverting to incremental
				// calculation of the mean value.
				incrementalMean = true
				mean = sum / count
				kahanC /= count
			}
			q := count / (count + 1)
			mean, kahanC = kahanSumInc(f.F/(count+1), q*mean, q*kahanC)
		}
		if incrementalMean {
			return mean + kahanC
		}
		count := float64(len(s.Floats))
		return sum/count + kahanC/count
	}), nil
}


Review comment (suggestion):
It was really hard to reconcile the algorithm in `avg` and this `avg_over_time`.
```suggestion
			count := float64(i + 2)
```
In avg_over_time we create groups with count==1 and the first number added makes it count==2. 

Here with this change we'd consider the 0th element in sum as count==1 and first element from the rest of the list as count==2. And also this way the `count` at the end as calculated by `len(s.Floats)` would mean the same thing.



Code after:
				}
				_, err = mean.Add(toAdd)
				if err != nil {
					return mean, err
				}
			}
			return mean, nil
		})
		if err != nil {
			metricName := firstSeries.Metric.Get(labels.MetricName)
			if errors.Is(err, histogram.ErrHistogramsIncompatibleSchema) {
				return enh.Out, annotations.New().Add(annotations.NewMixedExponentialCustomHistogramsWarning(metricName, args[0].PositionRange()))
			} else if errors.Is(err, histogram.ErrHistogramsIncompatibleBounds) {
				return enh.Out, annotations.New().Add(annotations.NewIncompatibleCustomBucketsHistogramsWarning(metricName, args[0].PositionRange()))
			}
		}
		return vec, nil
	}
	return aggrOverTime(vals, enh, func(s Series) float64 {
		var (
			// Pre-set the 1st sample to start the loop with the 2nd.
			sum, count      = s.Floats[0].F, 1.
			mean, kahanC    float64
			incrementalMean bool
		)
		for i, f := range s.Floats[1:] {
			count = float64(i + 2)
			if !incrementalMean {
				newSum, newC := kahanSumInc(f.F, sum, kahanC)
				// Perform regular mean calculation as long as
				// the sum doesn't overflow.
				if !math.IsInf(newSum, 0) {
					sum, kahanC = newSum, newC
					continue
				}
				// Handle overflow by reverting to incremental
				// calculation of the mean value.
				incrementalMean = true
				mean = sum / (count - 1)
				kahanC /= (count - 1)
			}
			q := (count - 1) / count
			mean, kahanC = kahanSumInc(f.F/count, q*mean, q*kahanC)
		}
		if incrementalMean {
			return mean + kahanC
		}
		return sum/count + kahanC/count
	}), nil
}