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

Code before:
			Metric:   sample.Metric,
			F:        sample.H.Sum / sample.H.Count,
			DropName: true,
		})
	}
	return enh.Out, nil
}

func histogramVariance(vals []parser.Value, enh *EvalNodeHelper, varianceToResult func(float64) float64) (Vector, annotations.Annotations) {
	vec := vals[0].(Vector)
	for _, sample := range vec {
		// Skip non-histogram samples.
		if sample.H == nil {
			continue
		}
		mean := sample.H.Sum / sample.H.Count
		var variance, cVariance float64
		it := sample.H.AllBucketIterator()
		for it.Next() {
			bucket := it.At()
			if bucket.Count == 0 {
				continue
			}
			var val float64
			switch {
			case bucket.Lower <= 0 && bucket.Upper >= 0:
				val = 0
			case sample.H.UsesCustomBuckets():
				// Use arithmetic mean in case of custom buckets.
				val = (bucket.Upper * bucket.Lower) / 2.0
			default:
				// Use geometric mean in case of standard exponential buckets.
				val = math.Sqrt(bucket.Upper * bucket.Lower)
				if bucket.Upper < 0 {
					val = -val
				}
			}
			delta := val - mean
			variance, cVariance = kahanSumInc(bucket.Count*delta*delta, variance, cVariance)
		}
		variance += cVariance
		variance /= sample.H.Count
		if !enh.enableDelayedNameRemoval {
			sample.Metric = sample.Metric.DropMetricName()
		}
		if varianceToResult != nil {
			variance = varianceToResult(variance)
		}
		enh.Out = append(enh.Out, Sample{
			Metric:   sample.Metric,
			F:        variance,

Review comment (refactor):
I have just realized that this case should come _after_ the `case sample.H.UsesCustomBuckets():` one. This here is meant for the zero bucket of standard exponential histograms (which is symmetric around zero), but not for a custom bucket that happens to include the zero point.

So please move this case one down, and to make the meaning clearer, I would add a comment like `// Use zero (effectively the arithmetic mean) in the zero bucket of a standard exponential histogram.`

Code after:
			F:        sample.H.Sum / sample.H.Count,
			DropName: true,
		})
	}
	return enh.Out, nil
}

func histogramVariance(vals []parser.Value, enh *EvalNodeHelper, varianceToResult func(float64) float64) (Vector, annotations.Annotations) {
	vec := vals[0].(Vector)
	for _, sample := range vec {
		// Skip non-histogram samples.
		if sample.H == nil {
			continue
		}
		mean := sample.H.Sum / sample.H.Count
		var variance, cVariance float64
		it := sample.H.AllBucketIterator()
		for it.Next() {
			bucket := it.At()
			if bucket.Count == 0 {
				continue
			}
			var val float64
			switch {
			case sample.H.UsesCustomBuckets():
				// Use arithmetic mean in case of custom buckets.
				val = (bucket.Upper + bucket.Lower) / 2.0
			case bucket.Lower <= 0 && bucket.Upper >= 0:
				// Use zero (effectively the arithmetic mean) in the zero bucket of a standard exponential histogram.
				val = 0
			default:
				// Use geometric mean in case of standard exponential buckets.
				val = math.Sqrt(bucket.Upper * bucket.Lower)
				if bucket.Upper < 0 {
					val = -val
				}
			}
			delta := val - mean
			variance, cVariance = kahanSumInc(bucket.Count*delta*delta, variance, cVariance)
		}
		variance += cVariance
		variance /= sample.H.Count
		if !enh.enableDelayedNameRemoval {
			sample.Metric = sample.Metric.DropMetricName()
		}
		if varianceToResult != nil {
			variance = varianceToResult(variance)
		}
		enh.Out = append(enh.Out, Sample{
			Metric:   sample.Metric,
			F:        variance,