Skip to content

Commit f313fa1

Browse files
committed
Use compensated sum to limit rounding errors
1 parent 7e4b7de commit f313fa1

1 file changed

Lines changed: 29 additions & 3 deletions

File tree

products/metrics/metrics-lib/src/main/java/datadog/metrics/impl/DDSketchHistogram.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,16 @@
1313
public class DDSketchHistogram implements Histogram {
1414
private final DDSketch sketch;
1515
private double sum;
16+
// We use a compensated sum to avoid accumulating rounding errors.
17+
// See https://en.wikipedia.org/wiki/Kahan_summation_algorithm.
18+
private double sumCompensation; // Low order bits of sum
19+
private double simpleSum; // Used to compute right sum for non-finite inputs
1620

1721
public DDSketchHistogram(DDSketch sketch) {
1822
this.sketch = sketch;
1923
this.sum = 0;
24+
this.simpleSum = 0;
25+
this.sumCompensation = 0;
2026
}
2127

2228
@Override
@@ -26,7 +32,15 @@ public double getCount() {
2632

2733
@Override
2834
public double getSum() {
29-
return sum;
35+
// Better error bounds to add both terms as the final sum
36+
final double tmp = sum + sumCompensation;
37+
if (Double.isNaN(tmp) && Double.isInfinite(simpleSum)) {
38+
// If the compensated sum is spuriously NaN from accumulating one or more same-signed infinite
39+
// values, return the correctly-signed infinity stored in simpleSum.
40+
return simpleSum;
41+
} else {
42+
return tmp;
43+
}
3044
}
3145

3246
@Override
@@ -37,13 +51,13 @@ public boolean isEmpty() {
3751
@Override
3852
public void accept(double value) {
3953
sketch.accept(value);
40-
sum += value;
54+
updateSum(value);
4155
}
4256

4357
@Override
4458
public void accept(double value, double count) {
4559
sketch.accept(value, count);
46-
sum += value * count;
60+
updateSum(value * count);
4761
}
4862

4963
@Override
@@ -112,4 +126,16 @@ public void clear() {
112126
public ByteBuffer serialize() {
113127
return sketch.serialize();
114128
}
129+
130+
private void updateSum(double value) {
131+
simpleSum += value;
132+
sumWithCompensation(value);
133+
}
134+
135+
private void sumWithCompensation(double value) {
136+
final double tmp = value - sumCompensation;
137+
final double velvel = sum + tmp; // Little wolf of rounding error
138+
sumCompensation = (velvel - sum) - tmp;
139+
sum = velvel;
140+
}
115141
}

0 commit comments

Comments
 (0)