diff --git a/src/main/java/org/apache/commons/math/util/MathUtils.java b/src/main/java/org/apache/commons/math/util/MathUtils.java index 46368dc9f..ad77a56eb 100644 --- a/src/main/java/org/apache/commons/math/util/MathUtils.java +++ b/src/main/java/org/apache/commons/math/util/MathUtils.java @@ -1621,9 +1621,9 @@ public final class MathUtils { * @return the L2 distance between the two points */ public static double distance(int[] p1, int[] p2) { - int sum = 0; + double sum = 0; for (int i = 0; i < p1.length; i++) { - final int dp = p1[i] - p2[i]; + final double dp = p1[i] - p2[i]; sum += dp * dp; } return Math.sqrt(sum); diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml index 3c94d22e9..bd1f4d344 100644 --- a/src/site/xdoc/changes.xml +++ b/src/site/xdoc/changes.xml @@ -39,6 +39,11 @@ The type attribute can be add,update,fix,remove. + + Fixed an overflow error in MathUtils.distance that was causing KMeansPlusPlusClusterer + to fail with a NullPointerException when component distances between points + exceeded Integer.MAXVALUE. + Added generationsEvolved property to GeneticAlgorithm to track the number of generations evolved by the evolve() method before reaching the StoppingCondition. diff --git a/src/test/java/org/apache/commons/math/stat/clustering/KMeansPlusPlusClustererTest.java b/src/test/java/org/apache/commons/math/stat/clustering/KMeansPlusPlusClustererTest.java index da1d8a93d..dfe89adef 100644 --- a/src/test/java/org/apache/commons/math/stat/clustering/KMeansPlusPlusClustererTest.java +++ b/src/test/java/org/apache/commons/math/stat/clustering/KMeansPlusPlusClustererTest.java @@ -93,5 +93,27 @@ public class KMeansPlusPlusClustererTest { assertTrue(cluster3Found); } + + /** + * JIRA: MATH-305 + * + * Two points, one cluster, one iteration + */ + @Test + public void testPerformClusterAnalysisDegenerate() { + KMeansPlusPlusClusterer transformer = new KMeansPlusPlusClusterer( + new Random(1746432956321l)); + EuclideanIntegerPoint[] points = new EuclideanIntegerPoint[] { + new EuclideanIntegerPoint(new int[] { 1959, 325100 }), + new EuclideanIntegerPoint(new int[] { 1960, 373200 }), }; + List> clusters = transformer.cluster(Arrays.asList(points), 1, 1); + assertEquals(1, clusters.size()); + assertEquals(2, (clusters.get(0).getPoints().size())); + EuclideanIntegerPoint pt1 = new EuclideanIntegerPoint(new int[] { 1959, 325100 }); + EuclideanIntegerPoint pt2 = new EuclideanIntegerPoint(new int[] { 1960, 373200 }); + assertTrue(clusters.get(0).getPoints().contains(pt1)); + assertTrue(clusters.get(0).getPoints().contains(pt2)); + + } }