This is an automated email from the ASF dual-hosted git repository. erans pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-numbers.git
commit a71294ae30dc69f99f3a0fe4a5daee45fdd448da Author: Gilles Sadowski <[email protected]> AuthorDate: Fri Jun 4 00:05:05 2021 +0200 Let angle normalization operate directly on "double". --- .../org/apache/commons/numbers/angle/Angle.java | 27 ++++--- .../apache/commons/numbers/angle/AngleTest.java | 84 +++++++++------------- .../apache/commons/numbers/angle/ReduceTest.java | 6 +- 3 files changed, 48 insertions(+), 69 deletions(-) diff --git a/commons-numbers-angle/src/main/java/org/apache/commons/numbers/angle/Angle.java b/commons-numbers-angle/src/main/java/org/apache/commons/numbers/angle/Angle.java index 95b12dc..f4afc36 100644 --- a/commons-numbers-angle/src/main/java/org/apache/commons/numbers/angle/Angle.java +++ b/commons-numbers-angle/src/main/java/org/apache/commons/numbers/angle/Angle.java @@ -16,7 +16,6 @@ */ package org.apache.commons.numbers.angle; -import java.util.function.UnaryOperator; import java.util.function.DoubleUnaryOperator; import java.util.function.DoubleSupplier; @@ -90,7 +89,7 @@ public abstract class Angle implements DoubleSupplier { /** Zero. */ public static final Turn ZERO = Turn.of(0d); /** Normalizing operator (result will be within the {@code [0, 1[} interval). */ - public static final UnaryOperator<Turn> WITHIN_0_AND_1 = normalizer(of(0d)); + public static final DoubleUnaryOperator WITHIN_0_AND_1 = normalizer(0d); /** * @param angle (in turns). @@ -149,9 +148,9 @@ public abstract class Angle implements DoubleSupplier { * @param lo Lower bound of the normalized interval. * @return the normalization operator. */ - public static UnaryOperator<Turn> normalizer(Turn lo) { - final Normalizer n = new Normalizer(lo.value, 1d); - return (Turn a) -> Turn.of(n.applyAsDouble(a.value)); + public static DoubleUnaryOperator normalizer(double lo) { + final Normalizer n = new Normalizer(lo, 1d); + return a -> n.applyAsDouble(a); } } @@ -166,9 +165,9 @@ public abstract class Angle implements DoubleSupplier { /** 2π. */ public static final Rad TWO_PI = Rad.of(2 * Math.PI); /** Normalizing operator (result will be within the <code>[0, 2π[</code> interval). */ - public static final UnaryOperator<Rad> WITHIN_0_AND_2PI = normalizer(of(0d)); + public static final DoubleUnaryOperator WITHIN_0_AND_2PI = normalizer(0d); /** Normalizing operator (result will be within the <code>[-π, π[</code> interval). */ - public static final UnaryOperator<Rad> WITHIN_MINUS_PI_AND_PI = normalizer(of(-Math.PI)); + public static final DoubleUnaryOperator WITHIN_MINUS_PI_AND_PI = normalizer(-Math.PI); /** * @param angle (in radians). @@ -227,9 +226,9 @@ public abstract class Angle implements DoubleSupplier { * @param lo Lower bound of the normalized interval. * @return the normalization operator. */ - public static UnaryOperator<Rad> normalizer(Rad lo) { - final Normalizer n = new Normalizer(lo.value, Angle.TWO_PI); - return (Rad a) -> Rad.of(n.applyAsDouble(a.value)); + public static DoubleUnaryOperator normalizer(double lo) { + final Normalizer n = new Normalizer(lo, Angle.TWO_PI); + return a -> n.applyAsDouble(a); } } @@ -240,7 +239,7 @@ public abstract class Angle implements DoubleSupplier { /** Zero. */ public static final Deg ZERO = Deg.of(0d); /** Normalizing operator (result will be within the {@code [0, 360[} interval). */ - public static final UnaryOperator<Deg> WITHIN_0_AND_360 = normalizer(of(0d)); + public static final DoubleUnaryOperator WITHIN_0_AND_360 = normalizer(0d); /** * @param angle (in degrees). @@ -299,9 +298,9 @@ public abstract class Angle implements DoubleSupplier { * @param lo Lower bound of the normalized interval. * @return the normalization operator. */ - public static UnaryOperator<Deg> normalizer(Deg lo) { - final Normalizer n = new Normalizer(lo.value, TURN_TO_DEG); - return (Deg a) -> Deg.of(n.applyAsDouble(a.value)); + public static DoubleUnaryOperator normalizer(double lo) { + final Normalizer n = new Normalizer(lo, TURN_TO_DEG); + return a -> n.applyAsDouble(a); } } diff --git a/commons-numbers-angle/src/test/java/org/apache/commons/numbers/angle/AngleTest.java b/commons-numbers-angle/src/test/java/org/apache/commons/numbers/angle/AngleTest.java index 92fda4b..f333f02 100644 --- a/commons-numbers-angle/src/test/java/org/apache/commons/numbers/angle/AngleTest.java +++ b/commons-numbers-angle/src/test/java/org/apache/commons/numbers/angle/AngleTest.java @@ -16,7 +16,7 @@ */ package org.apache.commons.numbers.angle; -import java.util.function.UnaryOperator; +import java.util.function.DoubleUnaryOperator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -27,11 +27,13 @@ import org.junit.jupiter.api.Test; class AngleTest { @Test void testConstants() { - Assertions.assertEquals(0d, Angle.Turn.ZERO.getAsDouble(), 0d); - Assertions.assertEquals(0d, Angle.Rad.ZERO.getAsDouble(), 0d); - Assertions.assertEquals(0d, Angle.Deg.ZERO.getAsDouble(), 0d); - Assertions.assertEquals(Math.PI, Angle.Rad.PI.getAsDouble(), 0d); - Assertions.assertEquals(2 * Math.PI, Angle.Rad.TWO_PI.getAsDouble(), 0d); + Assertions.assertEquals(0d, Angle.Turn.ZERO.getAsDouble()); + Assertions.assertEquals(0d, Angle.Rad.ZERO.getAsDouble()); + Assertions.assertEquals(0d, Angle.Deg.ZERO.getAsDouble()); + Assertions.assertEquals(Math.PI, Angle.Rad.PI.getAsDouble()); + Assertions.assertEquals(2 * Math.PI, Angle.Rad.TWO_PI.getAsDouble()); + Assertions.assertEquals(2 * Math.PI, Angle.TWO_PI); + Assertions.assertEquals(Math.PI / 2, Angle.PI_OVER_TWO); } @Test @@ -62,9 +64,7 @@ class AngleTest { final double twopi = 2 * Math.PI; for (double a = -15.0; a <= 15.0; a += 0.1) { for (double b = -15.0; b <= 15.0; b += 0.2) { - final Angle.Rad aA = Angle.Rad.of(a); - final Angle.Rad aB = Angle.Rad.of(b); - final double c = Angle.Rad.normalizer(aB).apply(aA).getAsDouble(); + final double c = Angle.Rad.normalizer(b).applyAsDouble(a); Assertions.assertTrue(b <= c); Assertions.assertTrue(c <= b + twopi); double twoK = Math.rint((a - c) / Math.PI); @@ -77,7 +77,7 @@ class AngleTest { void testNormalizeAboveZero1() { final double value = 1.25; final double expected = 0.25; - final double actual = Angle.Turn.WITHIN_0_AND_1.apply(Angle.Turn.of(value)).getAsDouble(); + final double actual = Angle.Turn.WITHIN_0_AND_1.applyAsDouble(value); final double tol = Math.ulp(expected); Assertions.assertEquals(expected, actual, tol); } @@ -85,7 +85,7 @@ class AngleTest { void testNormalizeAboveZero2() { final double value = -0.75; final double expected = 0.25; - final double actual = Angle.Turn.WITHIN_0_AND_1.apply(Angle.Turn.of(value)).getAsDouble(); + final double actual = Angle.Turn.WITHIN_0_AND_1.applyAsDouble(value); final double tol = Math.ulp(expected); Assertions.assertEquals(expected, actual, tol); } @@ -93,7 +93,7 @@ class AngleTest { void testNormalizeAboveZero3() { final double value = -0.5 + 1e-10; final double expected = 0.5 + 1e-10; - final double actual = Angle.Turn.WITHIN_0_AND_1.apply(Angle.Turn.of(value)).getAsDouble(); + final double actual = Angle.Turn.WITHIN_0_AND_1.applyAsDouble(value); final double tol = Math.ulp(expected); Assertions.assertEquals(expected, actual, tol); } @@ -101,53 +101,33 @@ class AngleTest { void testNormalizeAroundZero() { final double value = 5 * Math.PI / 4; final double expected = Math.PI * (1d / 4 - 1); - final double actual = Angle.Rad.WITHIN_MINUS_PI_AND_PI.apply(Angle.Rad.of(value)).getAsDouble(); + final double actual = Angle.Rad.WITHIN_MINUS_PI_AND_PI.applyAsDouble(value); final double tol = Math.ulp(expected); Assertions.assertEquals(expected, actual, tol); } @Test - void testNormalizeUpperAndLowerBounds() { - final UnaryOperator<Angle.Rad> nZero = Angle.Rad.WITHIN_MINUS_PI_AND_PI; - final UnaryOperator<Angle.Rad> nPi = Angle.Rad.WITHIN_0_AND_2PI; - - // act/assert - Assertions.assertEquals(-0.5, nZero.apply(Angle.Turn.of(-0.5).toRad()).toTurn().getAsDouble(), 0d); - Assertions.assertEquals(-0.5, nZero.apply(Angle.Turn.of(0.5).toRad()).toTurn().getAsDouble(), 0d); - - Assertions.assertEquals(-0.5, nZero.apply(Angle.Turn.of(-1.5).toRad()).toTurn().getAsDouble(), 0d); - Assertions.assertEquals(-0.5, nZero.apply(Angle.Turn.of(1.5).toRad()).toTurn().getAsDouble(), 0d); - - Assertions.assertEquals(0.0, nPi.apply(Angle.Turn.of(0).toRad()).toTurn().getAsDouble(), 0d); - Assertions.assertEquals(0.0, nPi.apply(Angle.Turn.of(1).toRad()).toTurn().getAsDouble(), 0d); - - Assertions.assertEquals(0.0, nPi.apply(Angle.Turn.of(-1).toRad()).toTurn().getAsDouble(), 0d); - Assertions.assertEquals(0.0, nPi.apply(Angle.Turn.of(2).toRad()).toTurn().getAsDouble(), 0d); - } - - @Test void testNormalizeVeryCloseToBounds() { - final UnaryOperator<Angle.Rad> nZero = Angle.Rad.WITHIN_MINUS_PI_AND_PI; - final UnaryOperator<Angle.Rad> nPi = Angle.Rad.WITHIN_0_AND_2PI; + final DoubleUnaryOperator nZero = Angle.Rad.WITHIN_MINUS_PI_AND_PI; + final DoubleUnaryOperator nPi = Angle.Rad.WITHIN_0_AND_2PI; // arrange final double pi = Math.PI; - final double twopi = 2 * pi; - double small = Math.ulp(twopi); + double small = Math.ulp(Angle.TWO_PI); double tiny = 5e-17; // pi + tiny = pi (the value is too small to add to pi) // act/assert - Assertions.assertEquals(twopi - small, nPi.apply(Angle.Rad.of(-small)).getAsDouble(), 0d); - Assertions.assertEquals(small, nPi.apply(Angle.Rad.of(small)).getAsDouble(), 0d); + Assertions.assertEquals(Angle.TWO_PI - small, nPi.applyAsDouble(-small)); + Assertions.assertEquals(small, nPi.applyAsDouble(small)); - Assertions.assertEquals(pi - small, nZero.apply(Angle.Rad.of(-pi - small)).getAsDouble(), 0d); - Assertions.assertEquals(-pi + small, nZero.apply(Angle.Rad.of(pi + small)).getAsDouble(), 0d); + Assertions.assertEquals(pi - small, nZero.applyAsDouble(-pi - small)); + Assertions.assertEquals(-pi + small, nZero.applyAsDouble(pi + small)); - Assertions.assertEquals(0d, nPi.apply(Angle.Rad.of(-tiny)).getAsDouble(), 0d); - Assertions.assertEquals(tiny, nPi.apply(Angle.Rad.of(tiny)).getAsDouble(), 0d); + Assertions.assertEquals(0d, nPi.applyAsDouble(-tiny)); + Assertions.assertEquals(tiny, nPi.applyAsDouble(tiny)); - Assertions.assertEquals(-pi, nZero.apply(Angle.Rad.of(-pi - tiny)).getAsDouble(), 0d); - Assertions.assertEquals(-pi, nZero.apply(Angle.Rad.of(pi + tiny)).getAsDouble(), 0d); + Assertions.assertEquals(-pi, nZero.applyAsDouble(-pi - tiny)); + Assertions.assertEquals(-pi, nZero.applyAsDouble(pi + tiny)); } @Test @@ -185,14 +165,14 @@ class AngleTest { final double belowZero = Math.nextDown(0); Assertions.assertEquals(aboveZero, - Angle.Rad.WITHIN_MINUS_PI_AND_PI.apply(Angle.Rad.of(aboveZero)).getAsDouble()); + Angle.Rad.WITHIN_MINUS_PI_AND_PI.applyAsDouble(aboveZero)); Assertions.assertEquals(aboveZero, - Angle.Rad.WITHIN_0_AND_2PI.apply(Angle.Rad.of(aboveZero)).getAsDouble()); + Angle.Rad.WITHIN_0_AND_2PI.applyAsDouble(aboveZero)); Assertions.assertEquals(belowZero, - Angle.Rad.WITHIN_MINUS_PI_AND_PI.apply(Angle.Rad.of(belowZero)).getAsDouble()); + Angle.Rad.WITHIN_MINUS_PI_AND_PI.applyAsDouble(belowZero)); Assertions.assertEquals(0, - Angle.Rad.WITHIN_0_AND_2PI.apply(Angle.Rad.of(belowZero)).getAsDouble()); + Angle.Rad.WITHIN_0_AND_2PI.applyAsDouble(belowZero)); } @Test @@ -201,14 +181,14 @@ class AngleTest { final double above = Math.nextUp(x); final double below = Math.nextDown(x); - final UnaryOperator<Angle.Rad> normalizer = Angle.Rad.normalizer(Angle.Rad.of(x)); + final DoubleUnaryOperator normalizer = Angle.Rad.normalizer(x); - Assertions.assertEquals(x, normalizer.apply(Angle.Rad.of(x)).getAsDouble()); - Assertions.assertEquals(above, normalizer.apply(Angle.Rad.of(above)).getAsDouble()); + Assertions.assertEquals(x, normalizer.applyAsDouble(x)); + Assertions.assertEquals(above, normalizer.applyAsDouble(above)); // "below" is so close to "x" that below + Math.PI = x + Math.PI // In this case, we can't return below + Math.PI because that is exactly equal to the // upper bound of the range. Instead, we must return the lower bound of x. - Assertions.assertEquals(x, normalizer.apply(Angle.Rad.of(below)).getAsDouble()); + Assertions.assertEquals(x, normalizer.applyAsDouble(below)); } } diff --git a/commons-numbers-angle/src/test/java/org/apache/commons/numbers/angle/ReduceTest.java b/commons-numbers-angle/src/test/java/org/apache/commons/numbers/angle/ReduceTest.java index 359248c..7ba98ac 100644 --- a/commons-numbers-angle/src/test/java/org/apache/commons/numbers/angle/ReduceTest.java +++ b/commons-numbers-angle/src/test/java/org/apache/commons/numbers/angle/ReduceTest.java @@ -16,7 +16,7 @@ */ package org.apache.commons.numbers.angle; -import java.util.function.UnaryOperator; +import java.util.function.DoubleUnaryOperator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -99,10 +99,10 @@ class ReduceTest { void testReduceComparedWithNormalize() { final double period = 2 * Math.PI; for (double lo = -15; lo <= 15; lo += 1) { - final UnaryOperator<Angle.Rad> n = Angle.Rad.normalizer(Angle.Rad.of(lo)); + final DoubleUnaryOperator n = Angle.Rad.normalizer(lo); final Reduce reduce = new Reduce(lo, period); for (double a = -15; a <= 15; a += 0.5) { - final double nA = n.apply(Angle.Rad.of(a)).getAsDouble(); + final double nA = n.applyAsDouble(a); final double r = reduce.applyAsDouble(a) + lo; Assertions.assertEquals(nA, r, Math.ulp(nA), "a=" + a + " lo=" + lo);
