diff --git a/core/src/main/java/com/tdunning/math/stats/Centroid.java b/core/src/main/java/com/tdunning/math/stats/Centroid.java index 654b3ea..eeefba6 100644 --- a/core/src/main/java/com/tdunning/math/stats/Centroid.java +++ b/core/src/main/java/com/tdunning/math/stats/Centroid.java @@ -81,7 +81,15 @@ public void add(double x, int w) { actualData.add(x); } count += w; - centroid += w * (x - centroid) / count; + // NOTE: The previous calculation was computed with `w * (x - centroid) / count;`. + // Now we calculate a factor here for cases where `count` might be a + // number like 3 that could lead to a repeating decimal and possible + // rounding issues. e.g. `count` starts as `0` (zero) and `w` as `3`. + // That could cause a calculation like `3 * (0.8046947099707735 - 0.0) / 3`. + // Calculating this we would get `0.8046947099707736` (same error for `w` + // equals to `6`, `11`, etc.) + double factor = (double) w / count; + centroid += factor * (x - centroid); } public double mean() { diff --git a/core/src/test/java/com/tdunning/math/stats/TDigestTest.java b/core/src/test/java/com/tdunning/math/stats/TDigestTest.java index ff13dd4..c61c3ec 100644 --- a/core/src/test/java/com/tdunning/math/stats/TDigestTest.java +++ b/core/src/test/java/com/tdunning/math/stats/TDigestTest.java @@ -548,6 +548,15 @@ public void testSorted() { } } + /** + * Issue: https://github.com/tdunning/t-digest/issues/169 + */ + public void testCentroidAdd() { + double x = 0.8046947099707735; + Centroid centroid = new Centroid(x, 3); + assertEquals(x, centroid.mean(), 0.0); + } + @Test public void testNaN() { final TDigest digest = factory().create();