diff --git a/src/changes/changes.xml b/src/changes/changes.xml index e201c3b4e..8574b496b 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -54,6 +54,9 @@ If the output is not quite correct, check for invisible trailing spaces! + + Method "cosAngle" in "o.a.c.m.util.MathArrays". + "KolmogorovSmirnovTest#ksSum(...)" returned wrong result in case the provided t-parameters was zero. This affected the calculation of "approximateP(...)" for diff --git a/src/main/java/org/apache/commons/math4/util/MathArrays.java b/src/main/java/org/apache/commons/math4/util/MathArrays.java index f4e7f4e4e..29a8c370d 100644 --- a/src/main/java/org/apache/commons/math4/util/MathArrays.java +++ b/src/main/java/org/apache/commons/math4/util/MathArrays.java @@ -242,6 +242,17 @@ public class MathArrays { return FastMath.sqrt(sum); } + /** + * Calculates the cosine of the angle between two vectors. + * + * @param v1 Cartesian coordinates of the first vector. + * @param v2 Cartesian coordinates of the second vector. + * @return the cosine of the angle between the vectors. + */ + public static double cosAngle(double[] v1, double[] v2) { + return linearCombination(v1, v2) / (safeNorm(v1) * safeNorm(v2)); + } + /** * Calculates the L2 (Euclidean) distance between two points. * diff --git a/src/test/java/org/apache/commons/math4/util/MathArraysTest.java b/src/test/java/org/apache/commons/math4/util/MathArraysTest.java index 3abd0cd13..9b837e07c 100644 --- a/src/test/java/org/apache/commons/math4/util/MathArraysTest.java +++ b/src/test/java/org/apache/commons/math4/util/MathArraysTest.java @@ -175,6 +175,61 @@ public class MathArraysTest { Assert.assertEquals(4, MathArrays.distanceInf(p1, p2)); } + @Test + public void testCosAngle2D() { + double expected; + + final double[] v1 = { 1, 0 }; + expected = 1; + Assert.assertEquals(expected, MathArrays.cosAngle(v1, v1), 0d); + + final double[] v2 = { 0, 1 }; + expected = 0; + Assert.assertEquals(expected, MathArrays.cosAngle(v1, v2), 0d); + + final double[] v3 = { 7, 7 }; + expected = Math.sqrt(2) / 2; + Assert.assertEquals(expected, MathArrays.cosAngle(v1, v3), 1e-15); + Assert.assertEquals(expected, MathArrays.cosAngle(v3, v2), 1e-15); + + final double[] v4 = { -5, 0 }; + expected = -1; + Assert.assertEquals(expected, MathArrays.cosAngle(v1, v4), 0); + + final double[] v5 = { -100, 100 }; + expected = 0; + Assert.assertEquals(expected, MathArrays.cosAngle(v3, v5), 0); + } + + @Test + public void testCosAngle3D() { + double expected; + + final double[] v1 = { 1, 1, 0 }; + expected = 1; + Assert.assertEquals(expected, MathArrays.cosAngle(v1, v1), 1e-15); + + final double[] v2 = { 1, 1, 1 }; + expected = Math.sqrt(2) / Math.sqrt(3); + Assert.assertEquals(expected, MathArrays.cosAngle(v1, v2), 1e-15); + } + + @Test + public void testCosAngleExtreme() { + double expected; + + final double tiny = 1e-200; + final double[] v1 = { tiny, tiny }; + final double big = 1e200; + final double[] v2 = { -big, -big }; + expected = -1; + Assert.assertEquals(expected, MathArrays.cosAngle(v1, v2), 1e-15); + + final double[] v3 = { big, -big }; + expected = 0; + Assert.assertEquals(expected, MathArrays.cosAngle(v1, v3), 1e-15); + } + @Test public void testCheckOrder() { MathArrays.checkOrder(new double[] {-15, -5.5, -1, 2, 15},