Fraction/BigFraction to validate input double in factory constructors

The double must not be nan or infinite.
diff --git a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/BigFraction.java b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/BigFraction.java
index 9a969c9..152a33e 100644
--- a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/BigFraction.java
+++ b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/BigFraction.java
@@ -47,6 +47,9 @@
     /** Serializable version identifier. */
     private static final long serialVersionUID = 20190701L;
 
+    /** Message for non-finite input double argument to factory constructors. */
+    private static final String NOT_FINITE = "Not finite: ";
+
     /** The numerator of this fraction reduced to lowest terms. */
     private final BigInteger numerator;
 
@@ -110,12 +113,17 @@
      * @param maxDenominator Maximum denominator value allowed.
      * @param maxIterations Maximum number of convergents.
      * @return a new instance.
+     * @throws IllegalArgumentException if the given {@code value} is NaN or infinite.
      * @throws ArithmeticException if the continued fraction failed to converge.
      */
     private static BigFraction from(final double value,
                                     final double epsilon,
                                     final int maxDenominator,
                                     final int maxIterations) {
+        if (!Double.isFinite(value)) {
+            throw new IllegalArgumentException(NOT_FINITE + value);
+        }
+
         final long overflow = Integer.MAX_VALUE;
         double r0 = value;
         long a0 = (long) Math.floor(r0);
@@ -187,7 +195,7 @@
     /**
      * Create a fraction given the double value.
      * <p>
-     * This factory method behaves <em>differently</em> from
+     * This factory method behaves <em>differently</em> to the method
      * {@link #from(double, double, int)}. It converts the double value
      * exactly, considering its internal bits representation. This works for all
      * values except NaN and infinities and does not requires any loop or
@@ -209,11 +217,8 @@
      * @see #from(double,double,int)
      */
     public static BigFraction from(final double value) {
-        if (Double.isNaN(value)) {
-            throw new IllegalArgumentException("Cannot convert NaN value");
-        }
-        if (Double.isInfinite(value)) {
-            throw new IllegalArgumentException("Cannot convert infinite value");
+        if (!Double.isFinite(value)) {
+            throw new IllegalArgumentException(NOT_FINITE + value);
         }
 
         final long bits = Double.doubleToLongBits(value);
@@ -266,6 +271,7 @@
      * @param epsilon Maximum error allowed. The resulting fraction is within
      * {@code epsilon} of {@code value}, in absolute terms.
      * @param maxIterations Maximum number of convergents.
+     * @throws IllegalArgumentException if the given {@code value} is NaN or infinite.
      * @throws ArithmeticException if the continued fraction failed to converge.
      * @return a new instance.
      *
diff --git a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java
index 8135438..0ec2009 100644
--- a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java
+++ b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java
@@ -47,6 +47,9 @@
     /** The default epsilon used for convergence. */
     private static final double DEFAULT_EPSILON = 1e-5;
 
+    /** Message for non-finite input double argument to factory constructors. */
+    private static final String NOT_FINITE = "Not finite: ";
+
     /** The numerator of this fraction reduced to lowest terms. */
     private final int numerator;
 
@@ -55,7 +58,7 @@
 
 
     /**
-     * Constructs an instance.
+     * Private constructor: Instances are created using factory methods.
      *
      * @param num Numerator.
      * @param den Denominator.
@@ -98,16 +101,17 @@
      * <p>
      * NOTE: This constructor is called with:
      * <ul>
-     *  <li>EITHER a valid epsilon value and the maxDenominator set to Integer.MAX_VALUE
-     *      (that way the maxDenominator has no effect).
-     *  <li>OR a valid maxDenominator value and the epsilon value set to zero
-     *      (that way epsilon only has effect if there is an exact match before
-     *      the maxDenominator value is reached).
+     *  <li>EITHER a valid epsilon value and the maxDenominator set to
+     *      Integer.MAX_VALUE (that way the maxDenominator has no effect)
+     *  <li>OR a valid maxDenominator value and the epsilon value set to
+     *      zero (that way epsilon only has effect if there is an exact
+     *      match before the maxDenominator value is reached).
      * </ul>
      * <p>
-     * It has been done this way so that the same code can be (re)used for both
-     * scenarios. However this could be confusing to users if it were part of
-     * the public API and this constructor should therefore remain PRIVATE.
+     * It has been done this way so that the same code can be reused for
+     * both scenarios. However this could be confusing to users if it
+     * were part of the public API and this method should therefore remain
+     * PRIVATE.
      * </p>
      *
      * <p>
@@ -115,18 +119,23 @@
      *     https://issues.apache.org/jira/browse/MATH-181
      * </p>
      *
-     * @param value the double value to convert to a fraction.
-     * @param epsilon maximum error allowed.  The resulting fraction is
-     * within {@code epsilon} of {@code value}, in absolute terms.
-     * @param maxDenominator maximum denominator value allowed.
-     * @param maxIterations maximum number of convergents
-     * @throws ArithmeticException if the continued fraction failed
-     * to converge.
+     * @param value Value to convert to a fraction.
+     * @param epsilon Maximum error allowed.
+     * The resulting fraction is within {@code epsilon} of {@code value},
+     * in absolute terms.
+     * @param maxDenominator Maximum denominator value allowed.
+     * @param maxIterations Maximum number of convergents.
+     * @throws IllegalArgumentException if the given {@code value} is NaN or infinite.
+     * @throws ArithmeticException if the continued fraction failed to converge.
      */
     private Fraction(final double value,
                      final double epsilon,
                      final int maxDenominator,
                      final int maxIterations) {
+        if (!Double.isFinite(value)) {
+            throw new IllegalArgumentException(NOT_FINITE + value);
+        }
+
         final long overflow = Integer.MAX_VALUE;
         double r0 = value;
         long a0 = (long)Math.floor(r0);
@@ -201,6 +210,7 @@
      * Create a fraction given the double value.
      *
      * @param value Value to convert to a fraction.
+     * @throws IllegalArgumentException if the given {@code value} is NaN or infinite.
      * @throws ArithmeticException if the continued fraction failed to
      * converge.
      * @return a new instance.
@@ -223,6 +233,7 @@
      * @param epsilon maximum error allowed.  The resulting fraction is within
      * {@code epsilon} of {@code value}, in absolute terms.
      * @param maxIterations maximum number of convergents
+     * @throws IllegalArgumentException if the given {@code value} is NaN or infinite.
      * @throws ArithmeticException if the continued fraction failed to
      * converge.
      * @return a new instance.
@@ -245,6 +256,7 @@
      *
      * @param value the double value to convert to a fraction.
      * @param maxDenominator The maximum allowed value for denominator
+     * @throws IllegalArgumentException if the given {@code value} is NaN or infinite.
      * @throws ArithmeticException if the continued fraction failed to
      * converge.
      * @return a new instance.
diff --git a/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/BigFractionTest.java b/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/BigFractionTest.java
index 62057a2..d2da883 100644
--- a/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/BigFractionTest.java
+++ b/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/BigFractionTest.java
@@ -128,6 +128,18 @@
         assertFraction(1, 2, BigFraction.from(0.5000000001, 10));
     }
 
+    @Test
+    public void testDoubleConstructorThrowsWithNonFinite() {
+        final double eps = 1e-5;
+        final int maxIterations = Integer.MAX_VALUE;
+        final int maxDenominator = Integer.MAX_VALUE;
+        for (final double value : new double[] {Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY}) {
+            Assertions.assertThrows(IllegalArgumentException.class, () -> BigFraction.from(value));
+            Assertions.assertThrows(IllegalArgumentException.class, () -> BigFraction.from(value, eps, maxIterations));
+            Assertions.assertThrows(IllegalArgumentException.class, () -> BigFraction.from(value, maxDenominator));
+        }
+    }
+
     // MATH-1029
     @Test
     public void testPositiveValueOverflow() {
diff --git a/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/FractionTest.java b/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/FractionTest.java
index 9d19663..5534d2e 100644
--- a/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/FractionTest.java
+++ b/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/FractionTest.java
@@ -67,6 +67,18 @@
         }
     }
 
+    @Test
+    public void testDoubleConstructorThrowsWithNonFinite() {
+        final double eps = 1e-5;
+        final int maxIterations = Integer.MAX_VALUE;
+        final int maxDenominator = Integer.MAX_VALUE;
+        for (final double value : new double[] {Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY}) {
+            Assertions.assertThrows(IllegalArgumentException.class, () -> Fraction.from(value));
+            Assertions.assertThrows(IllegalArgumentException.class, () -> Fraction.from(value, eps, maxIterations));
+            Assertions.assertThrows(IllegalArgumentException.class, () -> Fraction.from(value, maxDenominator));
+        }
+    }
+
     // MATH-181
     @Test
     public void testDigitLimitConstructor() throws Exception  {