You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2021/11/02 10:55:40 UTC

[commons-numbers] 02/02: Reuse the golden ratio continued fraction implementation.

This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-numbers.git

commit 924099e0c03ad21dce3cff85086142ae6d273f27
Author: aherbert <ah...@apache.org>
AuthorDate: Tue Nov 2 10:54:32 2021 +0000

    Reuse the golden ratio continued fraction implementation.
---
 .../numbers/fraction/ContinuedFractionTest.java    | 154 ++++++++++-----------
 1 file changed, 72 insertions(+), 82 deletions(-)

diff --git a/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/ContinuedFractionTest.java b/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/ContinuedFractionTest.java
index 79bf890..b9c21e0 100644
--- a/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/ContinuedFractionTest.java
+++ b/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/ContinuedFractionTest.java
@@ -29,47 +29,67 @@ class ContinuedFractionTest {
     /** Golden ratio constant. */
     private static final double GOLDEN_RATIO = 1.618033988749894848204586834365638117720309;
 
+    /**
+     * Evaluates the golden ratio.
+     *
+     * <pre>
+     * 1 +        1
+     *     ----------------
+     *     1 +      1
+     *         ------------
+     *         1 +     1
+     *              -------
+     *              1 + ...
+     * </pre>
+     *
+     * <p>This is used to test various conditions for the {@link ContinuedFraction}.
+     *
+     * @see <a href="https://mathworld.wolfram.com/GoldenRatio.html">MathWorld Golden
+     * Ratio equation 17</a>
+     */
+    private static class GoldenRatio extends ContinuedFraction {
+        private static final GoldenRatio INSTANCE = new GoldenRatio();
+
+        /**
+         * @return single instance of GoldenRatio
+         */
+        static GoldenRatio getInstance() {
+            return INSTANCE;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public double getA(int n, double x) {
+            return 1;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public double getB(int n, double x) {
+            return 1;
+        }
+    }
+
     @Test
     void testGoldenRatio() throws Exception {
-        ContinuedFraction cf = new ContinuedFraction() {
-            @Override
-            public double getA(int n, double x) {
-                return 1;
-            }
-
-            @Override
-            public double getB(int n, double x) {
-                return 1;
-            }
-        };
-
         final double eps = 1e-8;
-        double gr = cf.evaluate(0, eps);
-        Assertions.assertEquals(1.61803399, gr, eps);
+        final double gr = GoldenRatio.getInstance().evaluate(0, eps);
+        Assertions.assertEquals(GOLDEN_RATIO, gr, GOLDEN_RATIO * eps);
     }
 
     /**
      * Test an invalid epsilon (zero, negative or NaN).
      * See NUMBERS-173.
      *
-     * @param epsilon the epsilon
+     * @param epsilon Epsilon
      */
     @ParameterizedTest
     @ValueSource(doubles = {0, -1, Double.NaN})
     void testGoldenRatioEpsilonZero(double epsilon) {
-        ContinuedFraction cf = new ContinuedFraction() {
-            @Override
-            public double getA(int n, double x) {
-                return 1;
-            }
-
-            @Override
-            public double getB(int n, double x) {
-                return 1;
-            }
-        };
-
-        Assertions.assertEquals(GOLDEN_RATIO, cf.evaluate(0, epsilon), Math.ulp(GOLDEN_RATIO));
+        // An invalid epsilon is set to the minimum epsilon.
+        // It should converge to 1 ULP.
+        final double tolerance = Math.ulp(GOLDEN_RATIO);
+        Assertions.assertEquals(GOLDEN_RATIO, GoldenRatio.getInstance().evaluate(0, epsilon), tolerance);
     }
 
     @Test
@@ -84,7 +104,7 @@ class ContinuedFractionTest {
         //                    7
         //      = [4; 2, 6, 7]
 
-        ContinuedFraction cf = new ContinuedFraction() {
+        final ContinuedFraction cf = new ContinuedFraction() {
             @Override
             public double getA(int n, double x) {
                 return n <= 3 ? 1 : 0;
@@ -93,45 +113,39 @@ class ContinuedFractionTest {
             @Override
             public double getB(int n, double x) {
                 switch (n) {
-                    case 0: return 4;
-                    case 1: return 2;
-                    case 2: return 6;
-                    case 3: return 7;
-                    default: return 1;
+                case 0:
+                    return 4;
+                case 1:
+                    return 2;
+                case 2:
+                    return 6;
+                case 3:
+                    return 7;
+                default:
+                    return 1;
                 }
             }
         };
 
         final double eps = 1e-8;
-        double gr = cf.evaluate(0, eps, 5);
+        final double gr = cf.evaluate(0, eps, 5);
         Assertions.assertEquals(415.0 / 93.0, gr, eps);
     }
 
     @Test
     void testMaxIterationsThrows() throws Exception {
-        ContinuedFraction cf = new ContinuedFraction() {
-            @Override
-            public double getA(int n, double x) {
-                return 1;
-            }
-
-            @Override
-            public double getB(int n, double x) {
-                return 1;
-            }
-        };
+        final ContinuedFraction cf = GoldenRatio.getInstance();
 
         final double eps = 1e-8;
         final int maxIterations = 3;
-        final Throwable t = Assertions.assertThrows(FractionException.class,
-            () -> cf.evaluate(0, eps, maxIterations));
+        final Throwable t = Assertions.assertThrows(FractionException.class, () -> cf.evaluate(0, eps, maxIterations));
         assertExceptionMessageContains(t, "max");
     }
 
     @Test
     void testNaNThrows() throws Exception {
         // Create a NaN during the iteration
-        ContinuedFraction cf = new ContinuedFraction() {
+        final ContinuedFraction cf = new ContinuedFraction() {
             @Override
             public double getA(int n, double x) {
                 return 1;
@@ -144,16 +158,15 @@ class ContinuedFractionTest {
         };
 
         final double eps = 1e-8;
-        final Throwable t = Assertions.assertThrows(FractionException.class,
-            () -> cf.evaluate(0, eps, 5));
+        final Throwable t = Assertions.assertThrows(FractionException.class, () -> cf.evaluate(0, eps, 5));
         assertExceptionMessageContains(t, "nan");
     }
 
     @Test
     void testInfThrows() throws Exception {
         // Create an infinity during the iteration:
-        // a / cPrev  => a_1 / b_0 => Double.MAX_VALUE / 0.5
-        ContinuedFraction cf = new ContinuedFraction() {
+        // a / cPrev => a_1 / b_0 => Double.MAX_VALUE / 0.5
+        final ContinuedFraction cf = new ContinuedFraction() {
             @Override
             public double getA(int n, double x) {
                 return n == 0 ? 1 : Double.MAX_VALUE;
@@ -166,8 +179,7 @@ class ContinuedFractionTest {
         };
 
         final double eps = 1e-8;
-        final Throwable t = Assertions.assertThrows(FractionException.class,
-            () -> cf.evaluate(0, eps, 5));
+        final Throwable t = Assertions.assertThrows(FractionException.class, () -> cf.evaluate(0, eps, 5));
         assertExceptionMessageContains(t, "infinity");
     }
 
@@ -179,40 +191,18 @@ class ContinuedFractionTest {
     // NUMBERS-46
     @Test
     void testOneIteration() {
-        ContinuedFraction cf = new ContinuedFraction() {
-            @Override
-            public double getA(int n, double x) {
-                return 1;
-            }
-
-            @Override
-            public double getB(int n, double x) {
-                return 1;
-            }
-        };
-
         final double eps = 10;
-        double gr = cf.evaluate(0, eps, 1);
-        Assertions.assertEquals(1.61, gr, eps);
+        final double gr = GoldenRatio.getInstance().evaluate(0, eps, 1);
+        // Expected: 1 + 1 / 1
+        Assertions.assertEquals(2.0, gr);
     }
 
     // NUMBERS-46
     @Test
     void testTwoIterations() {
-        ContinuedFraction cf = new ContinuedFraction() {
-            @Override
-            public double getA(int n, double x) {
-                return 1;
-            }
-
-            @Override
-            public double getB(int n, double x) {
-                return 1;
-            }
-        };
-
         final double eps = 0.5;
-        double gr = cf.evaluate(0, eps, 2);
+        final double gr = GoldenRatio.getInstance().evaluate(0, eps, 2);
+        // Expected: 1 + 1 / (1 + 1 / 1)
         Assertions.assertEquals(1.5, gr);
     }
 }