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 2019/11/08 18:51:46 UTC

[commons-numbers] 19/32: [NUMBERS-78] Increase test coverage.

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 7775ba7b3188906c077be853bebaa01274565bd0
Author: aherbert <ah...@apache.org>
AuthorDate: Thu Nov 7 11:04:57 2019 +0000

    [NUMBERS-78] Increase test coverage.
    
    Added more tests using the C.99 standard.
    
    Fixed checkstyle.
    
    Use final.
---
 .../apache/commons/numbers/complex/Complex.java    | 391 ++++++++++-----
 .../commons/numbers/complex/CStandardTest.java     | 250 +++++++---
 .../commons/numbers/complex/ComplexTest.java       | 547 +++++++++++++--------
 .../apache/commons/numbers/complex/TestUtils.java  |  53 +-
 4 files changed, 822 insertions(+), 419 deletions(-)

diff --git a/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java b/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
index c47b510..083f774 100644
--- a/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
+++ b/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
@@ -25,18 +25,19 @@ import org.apache.commons.numbers.core.Precision;
 /**
  * Representation of a Complex number, i.e. a number which has both a
  * real and imaginary part.
- * <p>
- * Implementations of arithmetic operations handle {@code NaN} and
+ *
+ * <p>Implementations of arithmetic operations handle {@code NaN} and
  * infinite values according to the rules for {@link java.lang.Double}, i.e.
  * {@link #equals} is an equivalence relation for all instances that have
  * a {@code NaN} in either real or imaginary part, e.g. the following are
- * considered equal:
+ * considered equal:</p>
  * <ul>
  *  <li>{@code 1 + NaNi}</li>
  *  <li>{@code NaN + i}</li>
  *  <li>{@code NaN + NaNi}</li>
- * </ul><p>
- * Note that this contradicts the IEEE-754 standard for floating
+ * </ul>
+ *
+ * <p>Note that this contradicts the IEEE-754 standard for floating
  * point numbers (according to which the test {@code x == x} must fail if
  * {@code x} is {@code NaN}). The method
  * {@link org.apache.commons.numbers.core.Precision#equals(double,double,int)
@@ -44,6 +45,11 @@ import org.apache.commons.numbers.core.Precision;
  * IEEE-754 while this class conforms with the standard behavior for Java
  * object types.</p>
  *
+ * <p>Arithmetic in this class conforms to the C.99 standard for complex numbers
+ * defined in ISO/IEC 9899, Annex G.<p>
+ *
+ * @see <a href="http://www.open-std.org/JTC1/SC22/WG14/www/standards">
+ *    ISO/IEC 9899 - Programming languages - C</a>
  */
 public final class Complex implements Serializable  {
     /** The square root of -1, a.k.a. "i". */
@@ -52,8 +58,10 @@ public final class Complex implements Serializable  {
     public static final Complex ONE = new Complex(1, 0);
     /** A complex number representing zero. */
     public static final Complex ZERO = new Complex(0, 0);
-    /** A complex number representing "NaN + NaN i" */
+    /** A complex number representing "NaN + NaN i". */
     private static final Complex NAN = new Complex(Double.NaN, Double.NaN);
+    /** 3*&pi;/4. */
+    private static final double PI_3_OVER_4 = 0.75 * Math.PI;
     /** &pi;/2. */
     private static final double PI_OVER_2 = 0.5 * Math.PI;
     /** &pi;/4. */
@@ -111,9 +119,9 @@ public final class Complex implements Serializable  {
     /**
      * Creates a Complex from its polar representation.
      *
-     * If {@code r} is infinite and {@code theta} is finite, infinite or NaN
+     * <p>If {@code r} is infinite and {@code theta} is finite, infinite or NaN
      * values may be returned in parts of the result, following the rules for
-     * double arithmetic.
+     * double arithmetic.</p>
      *
      * <pre>
      * Examples:
@@ -127,9 +135,12 @@ public final class Complex implements Serializable  {
      * @param r the modulus of the complex number to create
      * @param theta the argument of the complex number to create
      * @return {@code Complex}
+     * @throws IllegalArgumentException if {@code r} is non-positive
      */
     public static Complex ofPolar(double r, double theta) {
-        checkNotNegative(r);
+        if (r <= 0) {
+            throw new IllegalArgumentException("Non-positive polar modulus argument: " + r);
+        }
         return new Complex(r * Math.cos(theta), r * Math.sin(theta));
     }
 
@@ -173,13 +184,13 @@ public final class Complex implements Serializable  {
         final double re;
         try {
             re = Double.parseDouble(elements[0]);
-        } catch (NumberFormatException ex) {
+        } catch (final NumberFormatException ex) {
             throw new ComplexParsingException("Could not parse real part" + elements[0]);
         }
         final double im;
         try {
             im = Double.parseDouble(elements[1]);
-        } catch (NumberFormatException ex) {
+        } catch (final NumberFormatException ex) {
             throw new ComplexParsingException("Could not parse imaginary part" + elements[1]);
         }
 
@@ -187,25 +198,41 @@ public final class Complex implements Serializable  {
     }
 
     /**
-     * Returns true if either real or imaginary component of the Complex
-     * is NaN.
+     * Returns true if either real or imaginary component of the Complex is NaN and the
+     * Complex is not infinite.
      *
-     * @return {@code true} is this instance contains NaN.
+     * @return {@code true} if this instance contains NaN and no infinite parts.
+     * @see Double#isNaN(double)
+     * @see #isInfinite()
      */
     public boolean isNaN() {
-        return Double.isNaN(real) ||
-            Double.isNaN(imaginary);
+        if (Double.isNaN(real) || Double.isNaN(imaginary)) {
+            return !isInfinite();
+        }
+        return false;
     }
 
     /**
-     * Returns true if either real or imaginary component of the Complex
-     * is infinite.
+     * Returns true if either real or imaginary component of the Complex is infinite.
+     *
+     * <p>Note: A complex or imaginary value with at least one infinite part is regarded
+     * as an infinity (even if its other part is a NaN).</p>
      *
      * @return {@code true} if this instance contains an infinite value.
+     * @see Double#isInfinite(double)
      */
     public boolean isInfinite() {
-        return Double.isInfinite(real) ||
-            Double.isInfinite(imaginary);
+        return Double.isInfinite(real) || Double.isInfinite(imaginary);
+    }
+
+    /**
+     * Returns true if both real and imaginary component of the Complex are finite.
+     *
+     * @return {@code true} if this instance contains finite values.
+     * @see Double#isFinite(double)
+     */
+    public boolean isFinite() {
+        return Double.isFinite(real) && Double.isFinite(imaginary);
     }
 
     /**
@@ -223,9 +250,8 @@ public final class Complex implements Serializable  {
         if (Double.isInfinite(real) ||
             Double.isInfinite(imaginary)) {
             return new Complex(Double.POSITIVE_INFINITY, 0);
-        } else {
-            return this;
         }
+        return this;
     }
 
      /**
@@ -237,16 +263,18 @@ public final class Complex implements Serializable  {
      * @return the absolute value.
      */
     public double abs() {
-        if (Math.abs(real) < Math.abs(imaginary)) {
-            final double q = real / imaginary;
-            return Math.abs(imaginary) * Math.sqrt(1 + q * q);
-        } else {
-            if (real == 0) {
-                return Math.abs(imaginary);
-            }
-            final double q = imaginary / real;
-            return Math.abs(real) * Math.sqrt(1 + q * q);
-        }
+        // Delegate
+        return Math.hypot(real, imaginary);
+
+        //if (Math.abs(real) < Math.abs(imaginary)) {
+        //    final double q = real / imaginary;
+        //    return Math.abs(imaginary) * Math.sqrt(1 + q * q);
+        //}
+        //if (real == 0) {
+        //    return Math.abs(imaginary);
+        //}
+        //final double q = imaginary / real;
+        //return Math.abs(real) * Math.sqrt(1 + q * q);
     }
 
     /**
@@ -290,6 +318,7 @@ public final class Complex implements Serializable  {
      /**
      * Returns the conjugate of this complex number
      * (C++11 grammar).
+     *
      * @return the conjugate of this complex object.
      * @see #conjugate()
      */
@@ -319,21 +348,20 @@ public final class Complex implements Serializable  {
      * @return {@code this / divisor}.
      */
     public Complex divide(Complex divisor) {
-
         double a = real;
         double b = imaginary;
         double c = divisor.getReal();
         double d = divisor.getImaginary();
         int ilogbw = 0;
-        double logbw = Math.log(Math.max(Math.abs(c), Math.abs(d))) / Math.log(2);
+        final double logbw = Math.log(Math.max(Math.abs(c), Math.abs(d))) / Math.log(2);
         if (!Double.isInfinite(logbw)) {
             ilogbw = (int)logbw;
             c = Math.scalb(c, -ilogbw);
             d = Math.scalb(d, -ilogbw);
         }
-        double denom = c*c + d*d;
-        double x = Math.scalb( (a*c + b*d) / denom, -ilogbw);
-        double y = Math.scalb( (b*c - a*d) / denom, -ilogbw);
+        final double denom = c * c + d * d;
+        double x = Math.scalb((a * c + b * d) / denom, -ilogbw);
+        double y = Math.scalb((b * c - a * d) / denom, -ilogbw);
         if (Double.isNaN(x) && Double.isNaN(y)) {
             if ((denom == 0.0) &&
                     (!Double.isNaN(a) || !Double.isNaN(b))) {
@@ -343,19 +371,17 @@ public final class Complex implements Serializable  {
                     !Double.isInfinite(c) && !Double.isInfinite(d)) {
                 a = Math.copySign(Double.isInfinite(a) ? 1.0 : 0.0, a);
                 b = Math.copySign(Double.isInfinite(b) ? 1.0 : 0.0, b);
-                x = Double.POSITIVE_INFINITY * (a*c + b*d);
-                y = Double.POSITIVE_INFINITY * (b*c - a*d);
+                x = Double.POSITIVE_INFINITY * (a * c + b * d);
+                y = Double.POSITIVE_INFINITY * (b * c - a * d);
             } else if (Double.isInfinite(logbw) &&
                     !Double.isInfinite(a) && !Double.isInfinite(b)) {
                 c = Math.copySign(Double.isInfinite(c) ? 1.0 : 0.0, c);
                 d = Math.copySign(Double.isInfinite(d) ? 1.0 : 0.0, d);
-                x = 0.0 * (a*c + b*d);
-                y = 0.0 * (b*c - a*d);
+                x = 0.0 * (a * c + b * d);
+                y = 0.0 * (b * c - a * d);
             }
         }
         return new Complex(x, y);
-
-
     }
 
     /**
@@ -386,16 +412,15 @@ public final class Complex implements Serializable  {
                 scaleQ = scale * q;
             }
             return new Complex(scaleQ, -scale);
-        } else {
-            final double q = imaginary / real;
-            final double scale = 1. / (imaginary * q + real);
-            double scaleQ = 0;
-            if (q != 0 &&
-                scale != 0) {
-                scaleQ = scale * q;
-            }
-            return new Complex(scale, -scaleQ);
         }
+        final double q = imaginary / real;
+        final double scale = 1. / (imaginary * q + real);
+        double scaleQ = 0;
+        if (q != 0 &&
+            scale != 0) {
+            scaleQ = scale * q;
+        }
+        return new Complex(scale, -scaleQ);
     }
 
     /**
@@ -427,8 +452,8 @@ public final class Complex implements Serializable  {
         if (this == other) {
             return true;
         }
-        if (other instanceof Complex){
-            Complex c = (Complex) other;
+        if (other instanceof Complex) {
+            final Complex c = (Complex) other;
             return equals(real, c.real) &&
                 equals(imaginary, c.imaginary);
         }
@@ -581,10 +606,10 @@ public final class Complex implements Serializable  {
         double b = imaginary;
         double c = factor.getReal();
         double d = factor.getImaginary();
-        final double ac = a*c;
-        final double bd = b*d;
-        final double ad = a*d;
-        final double bc = b*c;
+        final double ac = a * c;
+        final double bd = b * d;
+        final double ad = a * d;
+        final double bc = b * c;
         double x = ac - bd;
         double y = ad + bc;
         if (Double.isNaN(a) && Double.isNaN(b)) {
@@ -628,8 +653,8 @@ public final class Complex implements Serializable  {
                 recalc = true;
             }
             if (recalc) {
-                x = Double.POSITIVE_INFINITY * (a*c - b*d);
-                y = Double.POSITIVE_INFINITY * (a*d + b*c);
+                x = Double.POSITIVE_INFINITY * (a * c - b * d);
+                y = Double.POSITIVE_INFINITY * (a * d + b * c);
             }
         }
         return new Complex(x, y);
@@ -722,16 +747,14 @@ public final class Complex implements Serializable  {
             return new Complex(0, Double.NEGATIVE_INFINITY);
         } else if (real == Double.NEGATIVE_INFINITY &&
                    imaginary == Double.POSITIVE_INFINITY) {
-            return new Complex(Math.PI * 0.75, Double.NEGATIVE_INFINITY);
+            return new Complex(PI_3_OVER_4, Double.NEGATIVE_INFINITY);
         } else if (real == Double.POSITIVE_INFINITY &&
                    imaginary == Double.POSITIVE_INFINITY) {
             return new Complex(PI_OVER_4, Double.NEGATIVE_INFINITY);
-        } else if (real == Double.POSITIVE_INFINITY &&
-                   Double.isNaN(imaginary)) {
-            return new Complex(Double.NaN , Double.POSITIVE_INFINITY);
-        } else if (real == Double.NEGATIVE_INFINITY &&
+        } else if (Double.isInfinite(real) &&
                    Double.isNaN(imaginary)) {
-            return new Complex(Double.NaN, Double.NEGATIVE_INFINITY);
+            // Swap real and imaginary
+            return new Complex(Double.NaN, real);
         } else if (Double.isNaN(real) &&
                    imaginary == Double.POSITIVE_INFINITY) {
             return new Complex(Double.NaN, Double.NEGATIVE_INFINITY);
@@ -748,8 +771,13 @@ public final class Complex implements Serializable  {
      * @return the inverse sine of this complex number
      */
     public Complex asin() {
-        return sqrt1z().add(multiply(I)).log().multiply(I.negate());
+        // Define in terms of asinh
+        // asin(z) = -i asinh(iz)
+        return multiplyByI().asinh().multiplyByNegI();
+
+        //return sqrt1z().add(multiply(I)).log().multiply(I.negate());
     }
+
     /**
      * Compute the
      * <a href="http://mathworld.wolfram.com/InverseTangent.html">
@@ -761,7 +789,30 @@ public final class Complex implements Serializable  {
      * @return the inverse tangent of this complex number
      */
     public Complex atan() {
-        return add(I).divide(I.subtract(this)).log().multiply(I.multiply(0.5));
+        // Define in terms of atanh
+        // atan(z) = -i atanh(iz)
+        return multiplyByI().atanh().multiplyByNegI();
+
+        // This is not exact to 1 ulp
+        //return add(I).divide(I.subtract(this)).log().multiply(I.multiply(0.5));
+    }
+
+    /**
+     * Multiply the Complex by I.
+     *
+     * @return the result (iz)
+     */
+    private Complex multiplyByI() {
+        return new Complex(-imaginary, real);
+    }
+
+    /**
+     * Multiply the Complex by -I.
+     *
+     * @return the result (-iz)
+     */
+    private Complex multiplyByNegI() {
+        return new Complex(imaginary, -real);
     }
 
     /**
@@ -774,7 +825,7 @@ public final class Complex implements Serializable  {
      * </p><p>
      * @return the inverse hyperbolic cosine of this complex number
      */
-    public Complex asinh(){
+    public Complex asinh() {
         if (neitherInfiniteNorZeroNorNaN(real) &&
             imaginary == Double.POSITIVE_INFINITY) {
             return new Complex(Double.POSITIVE_INFINITY, PI_OVER_2);
@@ -807,7 +858,7 @@ public final class Complex implements Serializable  {
      * </p><p>
      * @return the inverse hyperbolic cosine of this complex number
      */
-    public Complex atanh(){
+    public Complex atanh() {
         if (real == 0 &&
             Double.isNaN(imaginary)) {
             return new Complex(0, Double.NaN);
@@ -832,17 +883,60 @@ public final class Complex implements Serializable  {
         }
         return add(ONE).divide(ONE.subtract(this)).log().multiply(0.5);
     }
-   /**
+
+    /**
      * Compute the
      * <a href="http://mathworld.wolfram.com/InverseHyperbolicCosine.html">
      * inverse hyperbolic cosine</a> of this complex number.
      * Implements the formula:
      * <p>
      * {@code acosh(z) = log(z+sqrt(z^2-1))}
-     * </p><p>
+     * </p>
+     *
      * @return the inverse hyperbolic cosine of this complex number
      */
     public Complex acosh() {
+        if (Double.isFinite(real)) {
+            if (real == 0 &&
+                imaginary == 0) {
+                return new Complex(0, PI_OVER_2);
+            }
+            if (imaginary == Double.POSITIVE_INFINITY) {
+                return new Complex(Double.POSITIVE_INFINITY, PI_OVER_2);
+            }
+            if (Double.isNaN(imaginary)) {
+                return NAN;
+            }
+        } else if (Double.isInfinite(real)) {
+            if (real == Double.NEGATIVE_INFINITY &&
+                positiveSignedFinite(imaginary)) {
+                return new Complex(Double.POSITIVE_INFINITY, Math.PI);
+            }
+            if (real == Double.POSITIVE_INFINITY &&
+                positiveSignedFinite(imaginary)) {
+                return new Complex(Double.POSITIVE_INFINITY, 0);
+            }
+            if (real == Double.NEGATIVE_INFINITY &&
+                imaginary == Double.POSITIVE_INFINITY) {
+                return new Complex(Double.POSITIVE_INFINITY, PI_3_OVER_4);
+            }
+            if (real == Double.POSITIVE_INFINITY &&
+                imaginary == Double.POSITIVE_INFINITY) {
+                return new Complex(Double.POSITIVE_INFINITY, PI_OVER_4);
+            }
+            if (Double.isNaN(imaginary)) {
+                return new Complex(Double.POSITIVE_INFINITY, Double.NaN);
+            }
+        } else if (Double.isNaN(real)) {
+            if (imaginary == Double.POSITIVE_INFINITY) {
+                return new Complex(Double.POSITIVE_INFINITY, Double.NaN);
+            }
+            if (Double.isFinite(imaginary) || Double.isNaN(imaginary)) {
+                // optionally raises the ‘‘invalid’’ floating-point exception, for finite y.
+                // No condition for imaginary as negative infinity
+                return NAN;
+            }
+        }
         return square().subtract(ONE).sqrt().add(this).log();
     }
 
@@ -861,7 +955,7 @@ public final class Complex implements Serializable  {
      * cosine</a> of this complex number.
      * Implements the formula:
      * <p>
-     *  {@code cos(a + bi) = cos(a)cosh(b) - sin(a)sinh(b)i}
+     * {@code cos(a + bi) = cos(a)cosh(b) - sin(a)sinh(b)i}
      * </p><p>
      * where the (real) functions on the right-hand side are
      * {@link Math#sin}, {@link Math#cos},
@@ -871,8 +965,12 @@ public final class Complex implements Serializable  {
      * @return the cosine of this complex number.
      */
     public Complex cos() {
-        return new Complex(Math.cos(real) * Math.cosh(imaginary),
-                           -Math.sin(real) * Math.sinh(imaginary));
+        // Define in terms of cosh
+        // cos(z) = cosh(iz)
+        return multiplyByI().cosh();
+
+        //return new Complex(Math.cos(real) * Math.cosh(imaginary),
+        //                  -Math.sin(real) * Math.sinh(imaginary));
     }
 
     /**
@@ -903,10 +1001,7 @@ public final class Complex implements Serializable  {
                    imaginary == 0) {
             return new Complex(Double.POSITIVE_INFINITY, 0);
         } else if (real == Double.POSITIVE_INFINITY &&
-                   imaginary == Double.POSITIVE_INFINITY) {
-            return new Complex(Double.POSITIVE_INFINITY, Double.NaN);
-        } else if (real == Double.POSITIVE_INFINITY &&
-                   Double.isNaN(imaginary)) {
+                   (imaginary == Double.POSITIVE_INFINITY || Double.isNaN(imaginary))) {
             return new Complex(Double.POSITIVE_INFINITY, Double.NaN);
         } else if (Double.isNaN(real) &&
                    imaginary == 0) {
@@ -941,19 +1036,16 @@ public final class Complex implements Serializable  {
                    imaginary == Double.POSITIVE_INFINITY) {
             return Complex.ZERO;
         } else if (real == Double.POSITIVE_INFINITY &&
-                   imaginary == Double.POSITIVE_INFINITY) {
+                   (imaginary == Double.POSITIVE_INFINITY || Double.isNaN(imaginary))) {
             return new Complex(Double.POSITIVE_INFINITY, Double.NaN);
         } else if (real == Double.NEGATIVE_INFINITY &&
                    Double.isNaN(imaginary)) {
             return Complex.ZERO;
-        } else if (real == Double.POSITIVE_INFINITY &&
-                   Double.isNaN(imaginary)) {
-            return new Complex(Double.POSITIVE_INFINITY, Double.NaN);
         } else if (Double.isNaN(real) &&
                    imaginary == 0) {
             return new Complex(Double.NaN, 0);
         }
-        double expReal = Math.exp(real);
+        final double expReal = Math.exp(real);
         return new Complex(expReal *  Math.cos(imaginary),
                            expReal * Math.sin(imaginary));
     }
@@ -979,11 +1071,10 @@ public final class Complex implements Serializable  {
         if (real == Double.POSITIVE_INFINITY &&
             imaginary == Double.POSITIVE_INFINITY) {
             return new Complex(Double.POSITIVE_INFINITY, PI_OVER_4);
-        } else if (real == Double.POSITIVE_INFINITY &&
-                   Double.isNaN(imaginary)) {
-            return new Complex(Double.POSITIVE_INFINITY, Double.NaN);
-        } else if (Double.isNaN(real) &&
-                   imaginary == Double.POSITIVE_INFINITY) {
+        } else if ((real == Double.POSITIVE_INFINITY &&
+                    Double.isNaN(imaginary)) ||
+                   ((Double.isNaN(real) &&
+                    imaginary == Double.POSITIVE_INFINITY))) {
             return new Complex(Double.POSITIVE_INFINITY, Double.NaN);
         }
         return new Complex(Math.log(abs()),
@@ -998,6 +1089,16 @@ public final class Complex implements Serializable  {
      *  @return the base 10 logarithm of <code>this</code>.
     */
     public Complex log10() {
+        // Same edge cases as log()
+        if (real == Double.POSITIVE_INFINITY &&
+            imaginary == Double.POSITIVE_INFINITY) {
+            return new Complex(Double.POSITIVE_INFINITY, PI_OVER_4);
+        } else if ((real == Double.POSITIVE_INFINITY &&
+                    Double.isNaN(imaginary)) ||
+                   ((Double.isNaN(real) &&
+                    imaginary == Double.POSITIVE_INFINITY))) {
+            return new Complex(Double.POSITIVE_INFINITY, Double.NaN);
+        }
         return new Complex(Math.log(abs()) / Math.log(10),
                            Math.atan2(imaginary, real));
     }
@@ -1019,14 +1120,14 @@ public final class Complex implements Serializable  {
     public Complex pow(Complex x) {
         if (real == 0 &&
             imaginary == 0) {
+            // This value is zero. Test the other.
             if (x.real > 0 &&
                 x.imaginary == 0) {
                 // 0 raised to positive number is 0
                 return ZERO;
-            } else {
-                // 0 raised to anything else is NaN
-                return NAN;
             }
+            // 0 raised to anything else is NaN
+            return NAN;
         }
         return log().multiply(x).exp();
     }
@@ -1038,16 +1139,16 @@ public final class Complex implements Serializable  {
      * @return <code>this<sup>x</sup></code>.
      * @see #pow(Complex)
      */
-     public Complex pow(double x) {
+    public Complex pow(double x) {
         if (real == 0 &&
             imaginary == 0) {
+            // This value is zero. Test the other.
             if (x > 0) {
                 // 0 raised to positive number is 0
                 return ZERO;
-            } else {
-                // 0 raised to anything else is NaN
-                return NAN;
             }
+            // 0 raised to anything else is NaN
+            return NAN;
         }
         return log().multiply(x).exp();
     }
@@ -1070,8 +1171,12 @@ public final class Complex implements Serializable  {
      * @return the sine of this complex number.
      */
     public Complex sin() {
-        return new Complex(Math.sin(real) * Math.cosh(imaginary),
-                           Math.cos(real) * Math.sinh(imaginary));
+        // Define in terms of sinh
+        // sin(z) = -i sinh(iz)
+        return multiplyByI().sinh().multiplyByNegI();
+
+        //return new Complex(Math.sin(real) * Math.cosh(imaginary),
+        //                   Math.cos(real) * Math.sinh(imaginary));
     }
 
     /**
@@ -1155,10 +1260,9 @@ public final class Complex implements Serializable  {
         final double t = Math.sqrt((Math.abs(real) + abs()) / 2);
         if (real >= 0) {
             return new Complex(t, imaginary / (2 * t));
-        } else {
-            return new Complex(Math.abs(imaginary) / (2 * t),
-                               Math.copySign(1d, imaginary) * t);
         }
+        return new Complex(Math.abs(imaginary) / (2 * t),
+                           Math.copySign(1d, imaginary) * t);
     }
 
     /**
@@ -1192,19 +1296,23 @@ public final class Complex implements Serializable  {
      * @return the tangent of {@code this}.
      */
     public Complex tan() {
-        if (imaginary > 20) {
-            return ONE;
-        }
-        if (imaginary < -20) {
-            return MINUS_I;
-        }
-
-        final double real2 = 2 * real;
-        final double imaginary2 = 2 * imaginary;
-        final double d = Math.cos(real2) + Math.cosh(imaginary2);
-
-        return new Complex(Math.sin(real2) / d,
-                           Math.sinh(imaginary2) / d);
+        // Define in terms of tanh
+        // tan(z) = -i tanh(iz)
+        return multiplyByI().tanh().multiplyByNegI();
+
+        //if (imaginary > 20) {
+        //    return ONE;
+        //}
+        //if (imaginary < -20) {
+        //    return MINUS_I;
+        //}
+        //
+        //final double real2 = 2 * real;
+        //final double imaginary2 = 2 * imaginary;
+        //final double d = Math.cos(real2) + Math.cosh(imaginary2);
+        //
+        //return new Complex(Math.sin(real2) / d,
+        //                   Math.sinh(imaginary2) / d);
     }
 
     /**
@@ -1224,6 +1332,11 @@ public final class Complex implements Serializable  {
      * @return the hyperbolic tangent of {@code this}.
      */
     public Complex tanh() {
+        // TODO - should these checks be made on real2 and imaginary2?
+        // Math.cos and Math.sin return NaN for infinity.
+        // Math.cosh returns positive infinity for infinity.
+        // Math.sinh returns the input infinity for infinity.
+
         if (real == Double.POSITIVE_INFINITY &&
             imaginary == Double.POSITIVE_INFINITY) {
             return ONE;
@@ -1260,14 +1373,16 @@ public final class Complex implements Serializable  {
      * @return the argument of {@code this}.
      */
     public double getArgument() {
+        // Delegate
         return Math.atan2(imaginary, real);
     }
 
     /**
-     * Compute the argument of this complex number.
-     * C++11 syntax
+     * Compute the argument of this complex number
+     * (C++11 grammar).
      *
      * @return the argument of {@code this}.
+     * @see #getArgument()
      */
     public double arg() {
         return getArgument();
@@ -1284,12 +1399,13 @@ public final class Complex implements Serializable  {
      * for <i>{@code k=0, 1, ..., n-1}</i>, where {@code abs} and {@code phi}
      * are respectively the {@link #abs() modulus} and
      * {@link #getArgument() argument} of this complex number.
-     * <p>
-     * If one or both parts of this complex number is NaN, a list with all
-     * all elements set to {@code NaN + NaN i} is returned.
+     *
+     * <p>If one or both parts of this complex number is NaN, a list with all
+     * all elements set to {@code NaN + NaN i} is returned.</p>
      *
      * @param n Degree of root.
      * @return a List of all {@code n}-th roots of {@code this}.
+     * @throws IllegalArgumentException if {@code n} is zero.
      */
     public List<Complex> nthRoot(int n) {
         if (n == 0) {
@@ -1305,7 +1421,7 @@ public final class Complex implements Serializable  {
         final double nthPhi = getArgument() / n;
         final double slice = 2 * Math.PI / n;
         double innerPart = nthPhi;
-        for (int k = 0; k < Math.abs(n) ; k++) {
+        for (int k = 0; k < Math.abs(n); k++) {
             // inner part
             final double realPart = nthRootOfAbs *  Math.cos(innerPart);
             final double imaginaryPart = nthRootOfAbs *  Math.sin(innerPart);
@@ -1329,17 +1445,6 @@ public final class Complex implements Serializable  {
     }
 
     /**
-     * Check that the argument is positive and throw a RuntimeException
-     * if it is not.
-     * @param arg {@code double} to check
-     */
-    private static void checkNotNegative(double arg) {
-        if (arg <= 0) {
-            throw new IllegalArgumentException("Complex: Non-positive argument");
-        }
-    }
-
-    /**
      * Returns {@code true} if the values are equal according to semantics of
      * {@link Double#equals(Object)}.
      *
@@ -1352,7 +1457,7 @@ public final class Complex implements Serializable  {
     }
 
     /**
-     * Check that a value meets all the following conditions:
+     * Check that a value meets all the following conditions.
      * <ul>
      *  <li>it is not {@code NaN},</li>
      *  <li>it is not infinite,</li>
@@ -1364,9 +1469,25 @@ public final class Complex implements Serializable  {
      * {@code false} otherwise.
      */
     private static boolean neitherInfiniteNorZeroNorNaN(double d) {
-        return !Double.isNaN(d) &&
-            !Double.isInfinite(d) &&
-            d != 0;
+        return Double.isFinite(d) && d != 0;
+    }
+
+    /**
+     * Check that a value meets all the following conditions.
+     * <ul>
+     *  <li>it is not {@code NaN},</li>
+     *  <li>it is not infinite,</li>
+     *  <li>it is positive signed,</li>
+     * </ul>
+     * 
+     * <p>Note: This is true for negative zero.</p>
+     *
+     * @param d Value.
+     * @return {@code true} if {@code d} meets all the conditions and
+     * {@code false} otherwise.
+     */
+    private static boolean positiveSignedFinite(double d) {
+        return Double.isFinite(d) && d >= 0;
     }
 
     /** See {@link #parse(String)}. */
diff --git a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CStandardTest.java b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CStandardTest.java
index d1e5a9c..e336b0c 100644
--- a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CStandardTest.java
+++ b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CStandardTest.java
@@ -17,93 +17,171 @@
 
 package org.apache.commons.numbers.complex;
 
+import org.apache.commons.numbers.core.Precision;
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.rng.simple.RandomSource;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
+/**
+ * Tests the standards defined by the C.99 standard for complex numbers
+ * defined in ISO/IEC 9899, Annex G.
+ *
+ * @see <a href="http://www.open-std.org/JTC1/SC22/WG14/www/standards">
+ *    ISO/IEC 9899 - Programming languages - C</a>
+ */
 public class CStandardTest {
 
+    // CHECKSTYLE: stop ConstantName
     private static final double inf = Double.POSITIVE_INFINITY;
     private static final double negInf = Double.NEGATIVE_INFINITY;
     private static final double nan = Double.NaN;
     private static final double piOverFour = Math.PI / 4.0;
     private static final double piOverTwo = Math.PI / 2.0;
-    private static final double threePiOverFour = 3.0*Math.PI/4.0;
-    private static final Complex oneOne = Complex.ofCartesian(1, 1);
-    private static final Complex oneZero = Complex.ofCartesian(1, 0);
-    private static final Complex oneInf = Complex.ofCartesian(1, inf);
-    private static final Complex oneNaN = Complex.ofCartesian(1, nan);
-    private static final Complex zeroInf = Complex.ofCartesian(0, inf);
-    private static final Complex zeroNegInf = Complex.ofCartesian(0,negInf);
-    private static final Complex zeroNaN = Complex.ofCartesian(0, nan);
-    private static final Complex zeroPiTwo = Complex.ofCartesian(0.0, piOverTwo);
-    private static final Complex negZeroZero = Complex.ofCartesian(-0.0, 0);
-    private static final Complex negI = Complex.ofCartesian(0.0, -1.0);
-    private static final Complex infOne = Complex.ofCartesian(inf, 1);
-    private static final Complex infZero = Complex.ofCartesian(inf, 0);
-    private static final Complex infNaN = Complex.ofCartesian(inf, nan);
-    private static final Complex infInf = Complex.ofCartesian(inf, inf);
-    private static final Complex infPiTwo = Complex.ofCartesian(inf, piOverTwo);
-    private static final Complex infPiFour = Complex.ofCartesian(inf, piOverFour);
-    private static final Complex infPi = Complex.ofCartesian(inf, Math.PI);
-    private static final Complex negInfInf = Complex.ofCartesian(negInf, inf);
-    private static final Complex negInfZero = Complex.ofCartesian(negInf, 0);
-    private static final Complex negInfOne = Complex.ofCartesian(negInf, 1);
-    private static final Complex negInfNaN = Complex.ofCartesian(negInf, nan);
-    private static final Complex negInfPosInf = Complex.ofCartesian(negInf, inf);
-    private static final Complex negInfPi = Complex.ofCartesian(negInf, Math.PI);
-    private static final Complex nanInf = Complex.ofCartesian(nan, inf);
-    private static final Complex nanNegInf = Complex.ofCartesian(nan, negInf);
-    private static final Complex nanZero = Complex.ofCartesian(nan, 0);
-    private static final Complex nanOne = Complex.ofCartesian(nan, 1);
-    private static final Complex piTwoNaN = Complex.ofCartesian(piOverTwo, nan);
-    private static final Complex piNegInf = Complex.ofCartesian(Math.PI, negInf);
-    private static final Complex piTwoNegInf = Complex.ofCartesian(piOverTwo, negInf);
-    private static final Complex piTwoNegZero = Complex.ofCartesian(piOverTwo, -0.0);
-    private static final Complex threePiFourNegInf = Complex.ofCartesian(threePiOverFour,negInf);
-    private static final Complex piFourNegInf = Complex.ofCartesian(piOverFour, negInf);
-    private static final Complex NAN = Complex.ofCartesian(nan, nan);
+    private static final double threePiOverFour = 3.0 * Math.PI / 4.0;
+    private static final Complex oneOne = complex(1, 1);
+    private static final Complex oneZero = complex(1, 0);
+    private static final Complex oneInf = complex(1, inf);
+    private static final Complex oneNaN = complex(1, nan);
+    private static final Complex zeroInf = complex(0, inf);
+    private static final Complex zeroNegInf = complex(0, negInf);
+    private static final Complex zeroNaN = complex(0, nan);
+    private static final Complex zeroPiTwo = complex(0.0, piOverTwo);
+    private static final Complex negZeroZero = complex(-0.0, 0);
+    private static final Complex negI = complex(0.0, -1.0);
+    private static final Complex infOne = complex(inf, 1);
+    private static final Complex infZero = complex(inf, 0);
+    private static final Complex infNaN = complex(inf, nan);
+    private static final Complex infInf = complex(inf, inf);
+    private static final Complex infPiTwo = complex(inf, piOverTwo);
+    private static final Complex infThreePiFour = complex(inf, threePiOverFour);
+    private static final Complex infPiFour = complex(inf, piOverFour);
+    private static final Complex infPi = complex(inf, Math.PI);
+    private static final Complex negInfInf = complex(negInf, inf);
+    private static final Complex negInfZero = complex(negInf, 0);
+    private static final Complex negInfOne = complex(negInf, 1);
+    private static final Complex negInfNaN = complex(negInf, nan);
+    private static final Complex negInfPosInf = complex(negInf, inf);
+    private static final Complex negInfPi = complex(negInf, Math.PI);
+    private static final Complex nanInf = complex(nan, inf);
+    private static final Complex nanNegInf = complex(nan, negInf);
+    private static final Complex nanZero = complex(nan, 0);
+    private static final Complex nanOne = complex(nan, 1);
+    private static final Complex piTwoNaN = complex(piOverTwo, nan);
+    private static final Complex piNegInf = complex(Math.PI, negInf);
+    private static final Complex piTwoNegInf = complex(piOverTwo, negInf);
+    private static final Complex piTwoNegZero = complex(piOverTwo, -0.0);
+    private static final Complex threePiFourNegInf = complex(threePiOverFour, negInf);
+    private static final Complex piFourNegInf = complex(piOverFour, negInf);
+    private static final Complex NAN = complex(nan, nan);
+    // CHECKSTYLE: resume ConstantName
 
-    public void assertComplex(Complex c1, Complex c2, double realTol, double imagTol) {
-        Assertions.assertEquals(c1.getReal(), c2.getReal(), realTol);
-        Assertions.assertEquals(c1.getImaginary(), c2.getImaginary(), imagTol);
+    /**
+     * Assert the two complex numbers have their real and imaginary components within
+     * the given tolerance.
+     *
+     * @param c1 the first complex
+     * @param c2 the second complex
+     * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
+     * values between the real (resp. imaginary) parts of {@code x} and
+     * {@code y}.
+     */
+    public void assertComplex(Complex c1, Complex c2, int maxUlps) {
+        if (!Precision.equals(c1.getReal(), c2.getReal(), maxUlps) ||
+            !Precision.equals(c1.getImaginary(), c2.getImaginary(), maxUlps)) {
+            Assertions.fail(c1 + " != " + c2);
+        }
     }
 
+    /**
+     * Assert the two complex numbers have equivalent real and imaginary components as
+     * defined by the {@code ==} operator.
+     *
+     * @param c1 the first complex
+     * @param c2 the second complex
+     */
     public void assertComplex(Complex c1, Complex c2) {
-        Assertions.assertEquals(c1.getReal(), c2.getReal(),0.0);
-        Assertions.assertEquals(c1.getImaginary(), c2.getImaginary(), 0.0);
+        // Use a delta of zero to allow comparison of -0.0 to 0.0
+        Assertions.assertEquals(c1.getReal(), c2.getReal(), 0.0, "real");
+        Assertions.assertEquals(c1.getImaginary(), c2.getImaginary(), 0.0, "imaginary");
     }
 
+    /**
+     * Utility to create a Complex.
+     *
+     * @param real the real
+     * @param imaginary the imaginary
+     * @return the complex
+     */
+    private static Complex complex(double real, double imaginary) {
+        return Complex.ofCartesian(real, imaginary);
+    }
 
     /**
-     * ISO C Standard G.6.3
+     * ISO C Standard G.6 (3).
      */
     @Test
     public void testSqrt1() {
-        Complex z1 = Complex.ofCartesian(-2.0, 0.0);
-        Complex z2 = Complex.ofCartesian(0.0, Math.sqrt(2));
-        assertComplex(z1.sqrt(), z2);
-        z1 = Complex.ofCartesian(-2.0, -0.0);
-        z2 = Complex.ofCartesian(0.0, -Math.sqrt(2));
-        assertComplex(z1.sqrt(), z2);
+        assertComplex(complex(-2.0, 0.0).sqrt(), complex(0.0, Math.sqrt(2)));
+        assertComplex(complex(-2.0, -0.0).sqrt(), complex(0.0, -Math.sqrt(2)));
     }
 
+    /**
+     * ISO C Standard G.6 (7).
+     */
     @Test
     public void testImplicitTrig() {
-        Complex z1 = Complex.ofReal(3.0);
-        Complex z2 = Complex.ofCartesian(0.0, 3.0);
-        assertComplex(z1.asin(), negI.multiply(z2.asinh()));
-        assertComplex(z1.atan(), negI.multiply(z2.atanh()), Math.ulp(1.0), Math.ulp(1.0));
-        assertComplex(z1.cos(), z2.cosh());
-        assertComplex(z1.sin(), negI.multiply(z2.sinh()));
-        assertComplex(z1.tan(), negI.multiply(z2.tanh()));
+        final UniformRandomProvider rng = RandomSource.create(RandomSource.SPLIT_MIX_64);
+        for (int i = 0; i < 100; i++) {
+            final double re = next(rng);
+            final double im = next(rng);
+            final Complex z = complex(re, im);
+            final Complex iz = Complex.I.multiply(z);
+            assertComplex(z.asin(), negI.multiply(iz.asinh()));
+            assertComplex(z.atan(), negI.multiply(iz.atanh()));
+            assertComplex(z.cos(), iz.cosh());
+            assertComplex(z.sin(), negI.multiply(iz.sinh()));
+            assertComplex(z.tan(), negI.multiply(iz.tanh()));
+        }
+    }
+
+    /**
+     * Create a number in the range {@code (-1,1)}.
+     *
+     * @param rng the random generator
+     * @return the number
+     */
+    private static double next(UniformRandomProvider rng) {
+        return rng.nextDouble() * (rng.nextBoolean() ? -1 : 1);
     }
 
     /**
-     * ISO C Standard G.6.1.1
+     * ISO C Standard G.6 (6) for abs().
+     * Defined by ISO C Standard F.9.4.3 hypot function.
+     */
+    @Test
+    public void testAbs() {
+        Assertions.assertEquals(inf, complex(inf, nan).abs());
+        Assertions.assertEquals(inf, complex(negInf, nan).abs());
+        final UniformRandomProvider rng = RandomSource.create(RandomSource.SPLIT_MIX_64);
+        for (int i = 0; i < 100; i++) {
+            final double x = next(rng);
+            final double y = next(rng);
+            Assertions.assertEquals(complex(x, y).abs(), complex(y, x).abs());
+            Assertions.assertEquals(complex(x, y).abs(), complex(x, -y).abs());
+            Assertions.assertEquals(Math.abs(x), complex(x, 0.0).abs());
+            Assertions.assertEquals(Math.abs(x), complex(x, -0.0).abs());
+            Assertions.assertEquals(inf, complex(inf, y).abs());
+            Assertions.assertEquals(inf, complex(negInf, y).abs());
+        }
+    }
+
+    /**
+     * ISO C Standard G.6.1.1.
      */
     @Test
     public void testAcos() {
-        assertComplex(oneOne.acos().conj(), oneOne.conj().acos(), Math.ulp(1.0), Math.ulp(1.0));
+        assertComplex(oneOne.acos().conj(), oneOne.conj().acos(), 1);
         assertComplex(Complex.ZERO.acos(), piTwoNegZero);
         assertComplex(negZeroZero.acos(), piTwoNegZero);
         assertComplex(zeroNaN.acos(), piTwoNaN);
@@ -121,7 +199,29 @@ public class CStandardTest {
     }
 
     /**
-     * ISO C Standard G.6.2.2
+     * ISO C Standard G.6.2.1.
+     */
+    @Test
+    public void testAcosh() {
+        assertComplex(oneOne.acosh().conj(), oneOne.conj().acosh(), 1);
+        assertComplex(Complex.ZERO.acosh(), zeroPiTwo);
+        assertComplex(negZeroZero.acosh(), zeroPiTwo);
+        assertComplex(oneInf.acosh(), infPiTwo);
+        assertComplex(zeroNaN.acosh(), NAN);
+        assertComplex(oneNaN.acosh(), NAN);
+        assertComplex(negInfOne.acosh(), infPi);
+        assertComplex(infOne.acosh(), infZero);
+        assertComplex(negInfPosInf.acosh(), infThreePiFour);
+        assertComplex(infInf.acosh(), infPiFour);
+        assertComplex(infNaN.acosh(), infNaN);
+        assertComplex(negInfNaN.acosh(), infNaN);
+        assertComplex(nanOne.acosh(), NAN);
+        assertComplex(nanInf.acosh(), infNaN);
+        assertComplex(NAN.acosh(), NAN);
+    }
+
+    /**
+     * ISO C Standard G.6.2.2.
      */
     @Test
     public void testAsinh() {
@@ -140,7 +240,7 @@ public class CStandardTest {
     }
 
     /**
-     * ISO C Standard G.6.2.3
+     * ISO C Standard G.6.2.3.
      */
     @Test
     public void testAtanh() {
@@ -148,7 +248,7 @@ public class CStandardTest {
         assertComplex(Complex.ZERO.atanh(), Complex.ZERO);
         assertComplex(zeroNaN.atanh(), zeroNaN);
         assertComplex(oneZero.atanh(), infZero);
-        assertComplex(oneInf.atanh(),zeroPiTwo);
+        assertComplex(oneInf.atanh(), zeroPiTwo);
         assertComplex(oneNaN.atanh(), NAN);
         assertComplex(infOne.atanh(), zeroPiTwo);
         assertComplex(infInf.atanh(), zeroPiTwo);
@@ -159,7 +259,7 @@ public class CStandardTest {
     }
 
     /**
-     * ISO C Standard G.6.2.4
+     * ISO C Standard G.6.2.4.
      */
     @Test
     public void testCosh() {
@@ -181,7 +281,7 @@ public class CStandardTest {
     }
 
     /**
-     * ISO C Standard G.6.2.5
+     * ISO C Standard G.6.2.5.
      */
     @Test
     public void testSinh() {
@@ -201,7 +301,7 @@ public class CStandardTest {
     }
 
     /**
-     * ISO C Standard G.6.2.6
+     * ISO C Standard G.6.2.6.
      */
     @Test
     public void testTanh() {
@@ -218,7 +318,7 @@ public class CStandardTest {
     }
 
     /**
-     * ISO C Standard G.6.3.1
+     * ISO C Standard G.6.3.1.
      */
     @Test
     public void testExp() {
@@ -239,7 +339,7 @@ public class CStandardTest {
     }
 
     /**
-     * ISO C Standard G.6.3.2
+     * ISO C Standard G.6.3.2.
      */
     @Test
     public void testLog() {
@@ -258,7 +358,27 @@ public class CStandardTest {
     }
 
     /**
-     * ISO C Standard G.6.4.2
+     * Same edge cases as log() since the real component is divided by Math.log(10) whic
+     * has no effect on infinite or nan.
+     */
+    @Test
+    public void testLog10() {
+        assertComplex(oneOne.log10().conj(), oneOne.conj().log10());
+        assertComplex(negZeroZero.log10(), negInfPi);
+        assertComplex(Complex.ZERO.log10(), negInfZero);
+        assertComplex(oneInf.log10(), infPiTwo);
+        assertComplex(oneNaN.log10(), NAN);
+        assertComplex(negInfOne.log10(), infPi);
+        assertComplex(infOne.log10(), infZero);
+        assertComplex(infInf.log10(), infPiFour);
+        assertComplex(infNaN.log10(), infNaN);
+        assertComplex(nanOne.log10(), NAN);
+        assertComplex(nanInf.log10(), infNaN);
+        assertComplex(NAN.log10(), NAN);
+    }
+
+    /**
+     * ISO C Standard G.6.4.2.
      */
     @Test
     public void testSqrt2() {
diff --git a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/ComplexTest.java b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/ComplexTest.java
index e8128dd..8078da8 100644
--- a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/ComplexTest.java
+++ b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/ComplexTest.java
@@ -18,15 +18,19 @@
 package org.apache.commons.numbers.complex;
 
 import java.util.List;
+
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.rng.simple.RandomSource;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
-
 /**
+ * Tests for {@link Complex}.
  */
 public class ComplexTest {
 
+    // CHECKSTYLE: stop ConstantName
     private static final double inf = Double.POSITIVE_INFINITY;
     private static final double neginf = Double.NEGATIVE_INFINITY;
     private static final double nan = Double.NaN;
@@ -51,44 +55,137 @@ public class ComplexTest {
     private static final Complex nanZero = Complex.ofCartesian(nan, 0);
     private static final Complex NAN = Complex.ofCartesian(nan, nan);
     private static final Complex INF = Complex.ofCartesian(inf, inf);
+    // CHECKSTYLE: resume ConstantName
+
+    /**
+     * Used to test the number category of a Complex.
+     */
+    private enum NumberType {
+        NAN,
+        INFINITE,
+        FINITE
+    }
 
     @Test
-    public void testConstructor() {
-        Complex z = Complex.ofCartesian(3.0, 4.0);
-        Assertions.assertEquals(3.0, z.getReal(), 1.0e-5);
-        Assertions.assertEquals(4.0, z.getImaginary(), 1.0e-5);
+    public void testCartesianConstructor() {
+        final Complex z = Complex.ofCartesian(3.0, 4.0);
+        Assertions.assertEquals(3.0, z.getReal());
+        Assertions.assertEquals(4.0, z.getImaginary());
     }
 
     @Test
-    public void testConstructorNaN() {
-        Complex z = Complex.ofCartesian(3.0, Double.NaN);
-        Assertions.assertTrue(z.isNaN());
+    public void testRealConstructor() {
+        final Complex z = Complex.ofReal(3.0);
+        Assertions.assertEquals(3.0, z.getReal());
+        Assertions.assertEquals(0.0, z.getImaginary());
+    }
 
-        z = Complex.ofCartesian(nan, 4.0);
-        Assertions.assertTrue(z.isNaN());
+    @Test
+    public void testPolarConstructor() {
+        final double r = 98765;
+        final double theta = 0.12345;
+        final Complex z = Complex.ofPolar(r, theta);
+        final Complex y = Complex.ofCis(theta);
+        Assertions.assertEquals(r * y.getReal(), z.getReal());
+        Assertions.assertEquals(r * y.getImaginary(), z.getImaginary());
 
-        z = Complex.ofCartesian(3.0, 4.0);
-        Assertions.assertFalse(z.isNaN());
+        Assertions.assertThrows(IllegalArgumentException.class, () -> Complex.ofPolar(-1, 0),
+            "negative modulus should not be allowed");
+    }
+
+    @Test
+    public void testCisConstructor() {
+        final double x = 0.12345;
+        final Complex z = Complex.ofCis(x);
+        Assertions.assertEquals(Math.cos(x), z.getReal());
+        Assertions.assertEquals(Math.sin(x), z.getImaginary());
+    }
+
+    @Test
+    public void testNumberType() {
+        assertNumberType(0, 0, NumberType.FINITE);
+        assertNumberType(1, 0, NumberType.FINITE);
+        assertNumberType(0, 1, NumberType.FINITE);
+
+        assertNumberType(inf, 0, NumberType.INFINITE);
+        assertNumberType(-inf, 0, NumberType.INFINITE);
+        assertNumberType(0, inf, NumberType.INFINITE);
+        assertNumberType(0, -inf, NumberType.INFINITE);
+        // A complex or imaginary value with at least one infinite part is regarded as an infinity
+        // (even if its other part is a NaN).
+        assertNumberType(inf, nan, NumberType.INFINITE);
+        assertNumberType(-inf, nan, NumberType.INFINITE);
+        assertNumberType(nan, inf, NumberType.INFINITE);
+        assertNumberType(nan, -inf, NumberType.INFINITE);
+
+        assertNumberType(nan, 0, NumberType.NAN);
+        assertNumberType(0, nan, NumberType.NAN);
+        assertNumberType(nan, nan, NumberType.NAN);
+    }
+
+    /**
+     * Assert the number type of the Complex created from the real and imaginary
+     * components.
+     *
+     * @param real the real component
+     * @param imaginary the imaginary component
+     * @param type the type
+     */
+    private static void assertNumberType(double real, double imaginary, NumberType type) {
+        final Complex z = Complex.ofCartesian(real, imaginary);
+        final boolean isNaN = z.isNaN();
+        final boolean isInfinite = z.isInfinite();
+        final boolean isFinite = z.isFinite();
+        // A number can be only one
+        int count = isNaN ? 1 : 0;
+        count += isInfinite ? 1 : 0;
+        count += isFinite ? 1 : 0;
+        Assertions.assertEquals(1, count,
+            () -> String.format("Complex can be only one type: isNaN=%s, isInfinite=%s, isFinite=%s: %s",
+                                isNaN, isInfinite, isFinite, z));
+        switch (type) {
+        case FINITE:
+            Assertions.assertTrue(isFinite, () -> "not finite: " + z);
+            break;
+        case INFINITE:
+            Assertions.assertTrue(isInfinite, () -> "not infinite: " + z);
+            break;
+        case NAN:
+            Assertions.assertTrue(isNaN, () -> "not nan: " + z);
+            break;
+        default:
+            Assertions.fail("Unknown number type");
+        }
+    }
+
+
+    @Test
+    public void testProj() {
+        final Complex z = Complex.ofCartesian(3.0, 4.0);
+        Assertions.assertSame(z, z.proj());
+        TestUtils.assertSame(infZero, Complex.ofCartesian(inf, 4.0).proj());
+        TestUtils.assertSame(infZero, Complex.ofCartesian(3.0, inf).proj());
     }
 
     @Test
     public void testAbs() {
-        Complex z = Complex.ofCartesian(3.0, 4.0);
+        final Complex z = Complex.ofCartesian(3.0, 4.0);
         Assertions.assertEquals(5.0, z.abs(), 1.0e-5);
     }
 
     @Test
     public void testAbsNaN() {
         Assertions.assertTrue(Double.isNaN(NAN.abs()));
-        Complex z = Complex.ofCartesian(inf, nan);
-        Assertions.assertTrue(Double.isNaN(z.abs()));
+        // The result is infinite if either argument is infinite
+        Assertions.assertEquals(inf, Complex.ofCartesian(inf, nan).abs());
+        Assertions.assertEquals(inf, Complex.ofCartesian(nan, inf).abs());
     }
 
     @Test
     public void testAdd() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        Complex y = Complex.ofCartesian(5.0, 6.0);
-        Complex z = x.add(y);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final Complex y = Complex.ofCartesian(5.0, 6.0);
+        final Complex z = x.add(y);
         Assertions.assertEquals(8.0, z.getReal(), 1.0e-5);
         Assertions.assertEquals(10.0, z.getImaginary(), 1.0e-5);
     }
@@ -96,8 +193,8 @@ public class ComplexTest {
     @Test
     public void testAddInf() {
         Complex x = Complex.ofCartesian(1, 1);
-        Complex z = Complex.ofCartesian(inf, 0);
-        Complex w = x.add(z);
+        final Complex z = Complex.ofCartesian(inf, 0);
+        final Complex w = x.add(z);
         Assertions.assertEquals(1, w.getImaginary(), 0);
         Assertions.assertEquals(inf, w.getReal(), 0);
 
@@ -108,26 +205,26 @@ public class ComplexTest {
 
     @Test
     public void testScalarAdd() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        double yDouble = 2.0;
-        Complex yComplex = Complex.ofReal(yDouble);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final double yDouble = 2.0;
+        final Complex yComplex = Complex.ofReal(yDouble);
         Assertions.assertEquals(x.add(yComplex), x.add(yDouble));
     }
 
     @Test
     public void testScalarAddNaN() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        double yDouble = Double.NaN;
-        Complex yComplex = Complex.ofReal(yDouble);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final double yDouble = Double.NaN;
+        final Complex yComplex = Complex.ofReal(yDouble);
         Assertions.assertEquals(x.add(yComplex), x.add(yDouble));
     }
 
     @Test
     public void testScalarAddInf() {
         Complex x = Complex.ofCartesian(1, 1);
-        double yDouble = Double.POSITIVE_INFINITY;
+        final double yDouble = Double.POSITIVE_INFINITY;
 
-        Complex yComplex = Complex.ofReal(yDouble);
+        final Complex yComplex = Complex.ofReal(yDouble);
         Assertions.assertEquals(x.add(yComplex), x.add(yDouble));
 
         x = Complex.ofCartesian(neginf, 0);
@@ -136,15 +233,15 @@ public class ComplexTest {
 
     @Test
     public void testConjugate() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        Complex z = x.conjugate();
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final Complex z = x.conjugate();
         Assertions.assertEquals(3.0, z.getReal(), 1.0e-5);
         Assertions.assertEquals(-4.0, z.getImaginary(), 1.0e-5);
     }
 
     @Test
     public void testConjugateNaN() {
-        Complex z = NAN.conjugate();
+        final Complex z = NAN.conjugate();
         Assertions.assertTrue(z.isNaN());
     }
 
@@ -158,100 +255,100 @@ public class ComplexTest {
 
     @Test
     public void testDivide() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        Complex y = Complex.ofCartesian(5.0, 6.0);
-        Complex z = x.divide(y);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final Complex y = Complex.ofCartesian(5.0, 6.0);
+        final Complex z = x.divide(y);
         Assertions.assertEquals(39.0 / 61.0, z.getReal(), 1.0e-5);
         Assertions.assertEquals(2.0 / 61.0, z.getImaginary(), 1.0e-5);
     }
 
     @Test
     public void testDivideReal() {
-        Complex x = Complex.ofCartesian(2d, 3d);
-        Complex y = Complex.ofCartesian(2d, 0d);
+        final Complex x = Complex.ofCartesian(2d, 3d);
+        final Complex y = Complex.ofCartesian(2d, 0d);
         Assertions.assertEquals(Complex.ofCartesian(1d, 1.5), x.divide(y));
 
     }
 
     @Test
     public void testDivideImaginary() {
-        Complex x = Complex.ofCartesian(2d, 3d);
-        Complex y = Complex.ofCartesian(0d, 2d);
+        final Complex x = Complex.ofCartesian(2d, 3d);
+        final Complex y = Complex.ofCartesian(0d, 2d);
         Assertions.assertEquals(Complex.ofCartesian(1.5d, -1d), x.divide(y));
     }
 
     @Test
     public void testDivideZero() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        Complex z = x.divide(Complex.ZERO);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final Complex z = x.divide(Complex.ZERO);
         Assertions.assertEquals(INF, z);
     }
 
     @Test
     public void testDivideZeroZero() {
-        Complex x = Complex.ofCartesian(0.0, 0.0);
-        Complex z = x.divide(Complex.ZERO);
+        final Complex x = Complex.ofCartesian(0.0, 0.0);
+        final Complex z = x.divide(Complex.ZERO);
         Assertions.assertEquals(NAN, z);
     }
 
     @Test
     public void testDivideNaN() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        Complex z = x.divide(NAN);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final Complex z = x.divide(NAN);
         Assertions.assertTrue(z.isNaN());
     }
 
     @Test
     public void testDivideNanInf() {
-       Complex z = oneInf.divide(Complex.ONE);
-       Assertions.assertTrue(Double.isNaN(z.getReal()));
-       Assertions.assertEquals(inf, z.getImaginary(), 0);
+        Complex z = oneInf.divide(Complex.ONE);
+        Assertions.assertTrue(Double.isNaN(z.getReal()));
+        Assertions.assertEquals(inf, z.getImaginary(), 0);
 
-       z = negInfNegInf.divide(oneNan);
-       Assertions.assertTrue(Double.isNaN(z.getReal()));
-       Assertions.assertTrue(Double.isNaN(z.getImaginary()));
+        z = negInfNegInf.divide(oneNan);
+        Assertions.assertTrue(Double.isNaN(z.getReal()));
+        Assertions.assertTrue(Double.isNaN(z.getImaginary()));
 
-       z = negInfInf.divide(Complex.ONE);
-       Assertions.assertTrue(Double.isInfinite(z.getReal()));
-       Assertions.assertTrue(Double.isInfinite(z.getImaginary()));
+        z = negInfInf.divide(Complex.ONE);
+        Assertions.assertTrue(Double.isInfinite(z.getReal()));
+        Assertions.assertTrue(Double.isInfinite(z.getImaginary()));
     }
 
     @Test
     public void testScalarDivide() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        double yDouble = 2.0;
-        Complex yComplex = Complex.ofReal(yDouble);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final double yDouble = 2.0;
+        final Complex yComplex = Complex.ofReal(yDouble);
         Assertions.assertEquals(x.divide(yComplex), x.divide(yDouble));
     }
 
     @Test
     public void testScalarDivideNaN() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        double yDouble = Double.NaN;
-        Complex yComplex = Complex.ofReal(yDouble);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final double yDouble = Double.NaN;
+        final Complex yComplex = Complex.ofReal(yDouble);
         Assertions.assertEquals(x.divide(yComplex), x.divide(yDouble));
     }
 
     @Test
     public void testScalarDivideZero() {
-        Complex x = Complex.ofCartesian(1,1);
+        final Complex x = Complex.ofCartesian(1, 1);
         TestUtils.assertEquals(x.divide(Complex.ZERO), x.divide(0), 0);
     }
 
     @Test
     public void testReciprocal() {
-        Complex z = Complex.ofCartesian(5.0, 6.0);
-        Complex act = z.reciprocal();
-        double expRe = 5.0 / 61.0;
-        double expIm = -6.0 / 61.0;
+        final Complex z = Complex.ofCartesian(5.0, 6.0);
+        final Complex act = z.reciprocal();
+        final double expRe = 5.0 / 61.0;
+        final double expIm = -6.0 / 61.0;
         Assertions.assertEquals(expRe, act.getReal(), Math.ulp(expRe));
         Assertions.assertEquals(expIm, act.getImaginary(), Math.ulp(expIm));
     }
 
     @Test
     public void testReciprocalReciprocal() {
-        Complex z = Complex.ofCartesian(5.0, 6.0);
-        Complex zRR = z.reciprocal().reciprocal();
+        final Complex z = Complex.ofCartesian(5.0, 6.0);
+        final Complex zRR = z.reciprocal().reciprocal();
         final double tol = 1e-14;
         Assertions.assertEquals(zRR.getReal(), z.getReal(), tol);
         Assertions.assertEquals(zRR.getImaginary(), z.getImaginary(), tol);
@@ -259,13 +356,13 @@ public class ComplexTest {
 
     @Test
     public void testReciprocalReal() {
-        Complex z = Complex.ofCartesian(-2.0, 0.0);
+        final Complex z = Complex.ofCartesian(-2.0, 0.0);
         Assertions.assertTrue(Complex.equals(Complex.ofCartesian(-0.5, 0.0), z.reciprocal()));
     }
 
     @Test
     public void testReciprocalImaginary() {
-        Complex z = Complex.ofCartesian(0.0, -2.0);
+        final Complex z = Complex.ofCartesian(0.0, -2.0);
         Assertions.assertEquals(Complex.ofCartesian(0.0, 0.5), z.reciprocal());
     }
 
@@ -276,9 +373,9 @@ public class ComplexTest {
 
     @Test
     public void testMultiply() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        Complex y = Complex.ofCartesian(5.0, 6.0);
-        Complex z = x.multiply(y);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final Complex y = Complex.ofCartesian(5.0, 6.0);
+        final Complex z = x.multiply(y);
         Assertions.assertEquals(-9.0, z.getReal(), 1.0e-5);
         Assertions.assertEquals(38.0, z.getImaginary(), 1.0e-5);
     }
@@ -291,26 +388,26 @@ public class ComplexTest {
 
     @Test
     public void testScalarMultiply() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        double yDouble = 2.0;
-        Complex yComplex = Complex.ofReal(yDouble);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final double yDouble = 2.0;
+        final Complex yComplex = Complex.ofReal(yDouble);
         Assertions.assertEquals(x.multiply(yComplex), x.multiply(yDouble));
-        int zInt = -5;
-        Complex zComplex = Complex.ofReal(zInt);
+        final int zInt = -5;
+        final Complex zComplex = Complex.ofReal(zInt);
         Assertions.assertEquals(x.multiply(zComplex), x.multiply(zInt));
     }
 
     @Test
     public void testScalarMultiplyNaN() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        double yDouble = Double.NaN;
-        Complex yComplex = Complex.ofReal(yDouble);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final double yDouble = Double.NaN;
+        final Complex yComplex = Complex.ofReal(yDouble);
         Assertions.assertEquals(x.multiply(yComplex), x.multiply(yDouble));
     }
 
     @Test
     public void testScalarMultiplyInf() {
-        Complex x = Complex.ofCartesian(1, 1);
+        final Complex x = Complex.ofCartesian(1, 1);
         double yDouble = Double.POSITIVE_INFINITY;
         Complex yComplex = Complex.ofReal(yDouble);
         Assertions.assertEquals(x.multiply(yComplex), x.multiply(yDouble));
@@ -322,23 +419,23 @@ public class ComplexTest {
 
     @Test
     public void testNegate() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        Complex z = x.negate();
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final Complex z = x.negate();
         Assertions.assertEquals(-3.0, z.getReal(), 1.0e-5);
         Assertions.assertEquals(-4.0, z.getImaginary(), 1.0e-5);
     }
 
     @Test
     public void testNegateNaN() {
-        Complex z = NAN.negate();
+        final Complex z = NAN.negate();
         Assertions.assertTrue(z.isNaN());
     }
 
     @Test
     public void testSubtract() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        Complex y = Complex.ofCartesian(5.0, 6.0);
-        Complex z = x.subtract(y);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final Complex y = Complex.ofCartesian(5.0, 6.0);
+        final Complex z = x.subtract(y);
         Assertions.assertEquals(-2.0, z.getReal(), 1.0e-5);
         Assertions.assertEquals(-2.0, z.getImaginary(), 1.0e-5);
     }
@@ -346,8 +443,8 @@ public class ComplexTest {
     @Test
     public void testSubtractInf() {
         Complex x = Complex.ofCartesian(1, 1);
-        Complex z = Complex.ofCartesian(neginf, 0);
-        Complex w = x.subtract(z);
+        final Complex z = Complex.ofCartesian(neginf, 0);
+        final Complex w = x.subtract(z);
         Assertions.assertEquals(1, w.getImaginary(), 0);
         Assertions.assertEquals(inf, w.getReal(), 0);
 
@@ -357,25 +454,25 @@ public class ComplexTest {
 
     @Test
     public void testScalarSubtract() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        double yDouble = 2.0;
-        Complex yComplex = Complex.ofReal(yDouble);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final double yDouble = 2.0;
+        final Complex yComplex = Complex.ofReal(yDouble);
         Assertions.assertEquals(x.subtract(yComplex), x.subtract(yDouble));
     }
 
     @Test
     public void testScalarSubtractNaN() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        double yDouble = Double.NaN;
-        Complex yComplex = Complex.ofReal(yDouble);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final double yDouble = Double.NaN;
+        final Complex yComplex = Complex.ofReal(yDouble);
         Assertions.assertEquals(x.subtract(yComplex), x.subtract(yDouble));
     }
 
     @Test
     public void testScalarSubtractInf() {
         Complex x = Complex.ofCartesian(1, 1);
-        double yDouble = Double.POSITIVE_INFINITY;
-        Complex yComplex = Complex.ofReal(yDouble);
+        final double yDouble = Double.POSITIVE_INFINITY;
+        final Complex yComplex = Complex.ofReal(yDouble);
         Assertions.assertEquals(x.subtract(yComplex), x.subtract(yDouble));
 
         x = Complex.ofCartesian(neginf, 0);
@@ -385,33 +482,33 @@ public class ComplexTest {
 
     @Test
     public void testEqualsNull() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
         Assertions.assertNotEquals(null, x);
     }
 
     @Test
     public void testFloatingPointEqualsPrecondition1() {
         Assertions.assertThrows(NullPointerException.class,
-                () -> Complex.equals(Complex.ofCartesian(3.0, 4.0), null, 3)
+            () -> Complex.equals(Complex.ofCartesian(3.0, 4.0), null, 3)
         );
-
     }
+
     @Test
     public void testFloatingPointEqualsPrecondition2() {
         Assertions.assertThrows(NullPointerException.class,
-                () -> Complex.equals(null, Complex.ofCartesian(3.0, 4.0), 3)
+            () -> Complex.equals(null, Complex.ofCartesian(3.0, 4.0), 3)
         );
     }
 
     @Test
     public void testEqualsClass() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
         Assertions.assertFalse(x.equals(this));
     }
 
     @Test
     public void testEqualsSame() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
         Assertions.assertEquals(x, x);
     }
 
@@ -494,22 +591,22 @@ public class ComplexTest {
 
     @Test
     public void testEqualsTrue() {
-        Complex x = Complex.ofCartesian(3.0, 4.0);
-        Complex y = Complex.ofCartesian(3.0, 4.0);
+        final Complex x = Complex.ofCartesian(3.0, 4.0);
+        final Complex y = Complex.ofCartesian(3.0, 4.0);
         Assertions.assertEquals(x, y);
     }
 
     @Test
     public void testEqualsRealDifference() {
-        Complex x = Complex.ofCartesian(0.0, 0.0);
-        Complex y = Complex.ofCartesian(0.0 + Double.MIN_VALUE, 0.0);
+        final Complex x = Complex.ofCartesian(0.0, 0.0);
+        final Complex y = Complex.ofCartesian(0.0 + Double.MIN_VALUE, 0.0);
         Assertions.assertNotEquals(x, y);
     }
 
     @Test
     public void testEqualsImaginaryDifference() {
-        Complex x = Complex.ofCartesian(0.0, 0.0);
-        Complex y = Complex.ofCartesian(0.0, 0.0 + Double.MIN_VALUE);
+        final Complex x = Complex.ofCartesian(0.0, 0.0);
+        final Complex y = Complex.ofCartesian(0.0, 0.0 + Double.MIN_VALUE);
         Assertions.assertNotEquals(x, y);
     }
 
@@ -520,8 +617,8 @@ public class ComplexTest {
         Assertions.assertNotEquals(x.hashCode(), y.hashCode());
         y = Complex.ofCartesian(0.0 + Double.MIN_VALUE, 0.0);
         Assertions.assertNotEquals(x.hashCode(), y.hashCode());
-        Complex realNan = Complex.ofCartesian(Double.NaN, 0.0);
-        Complex imaginaryNan = Complex.ofCartesian(0.0, Double.NaN);
+        final Complex realNan = Complex.ofCartesian(Double.NaN, 0.0);
+        final Complex imaginaryNan = Complex.ofCartesian(0.0, Double.NaN);
         Assertions.assertEquals(realNan.hashCode(), imaginaryNan.hashCode());
         Assertions.assertEquals(imaginaryNan.hashCode(), NAN.hashCode());
 
@@ -542,74 +639,86 @@ public class ComplexTest {
     }
 
     @Test
-    @Disabled
-    public void testJava() {// TODO more debug
+    @Disabled("Used to output the java environment")
+    public void testJava() {
+        // CHECKSTYLE: stop Regexp
         System.out.println(">>testJava()");
         // MathTest#testExpSpecialCases() checks the following:
         // Assert.assertEquals("exp of -infinity should be 0.0", 0.0, Math.exp(Double.NEGATIVE_INFINITY), Precision.EPSILON);
         // Let's check how well Math works:
-        System.out.println("Math.exp="+Math.exp(Double.NEGATIVE_INFINITY));
-        String props[] = {
-        "java.version", //    Java Runtime Environment version
-        "java.vendor", // Java Runtime Environment vendor
-        "java.vm.specification.version", //   Java Virtual Machine specification version
-        "java.vm.specification.vendor", //    Java Virtual Machine specification vendor
-        "java.vm.specification.name", //  Java Virtual Machine specification name
-        "java.vm.version", // Java Virtual Machine implementation version
-        "java.vm.vendor", //  Java Virtual Machine implementation vendor
-        "java.vm.name", //    Java Virtual Machine implementation name
-        "java.specification.version", //  Java Runtime Environment specification version
-        "java.specification.vendor", //   Java Runtime Environment specification vendor
-        "java.specification.name", // Java Runtime Environment specification name
-        "java.class.version", //  Java class format version number
+        System.out.println("Math.exp=" + Math.exp(Double.NEGATIVE_INFINITY));
+        final String[] props = {
+            "java.version", //    Java Runtime Environment version
+            "java.vendor", // Java Runtime Environment vendor
+            "java.vm.specification.version", //   Java Virtual Machine specification version
+            "java.vm.specification.vendor", //    Java Virtual Machine specification vendor
+            "java.vm.specification.name", //  Java Virtual Machine specification name
+            "java.vm.version", // Java Virtual Machine implementation version
+            "java.vm.vendor", //  Java Virtual Machine implementation vendor
+            "java.vm.name", //    Java Virtual Machine implementation name
+            "java.specification.version", //  Java Runtime Environment specification version
+            "java.specification.vendor", //   Java Runtime Environment specification vendor
+            "java.specification.name", // Java Runtime Environment specification name
+            "java.class.version", //  Java class format version number
         };
-        for(String t : props) {
+        for (final String t : props) {
             System.out.println(t + "=" + System.getProperty(t));
         }
         System.out.println("<<testJava()");
+        // CHECKSTYLE: resume Regexp
     }
 
-
     @Test
-    public void testScalarPow() {
-        Complex x = Complex.ofCartesian(3, 4);
-        double yDouble = 5.0;
-        Complex yComplex = Complex.ofReal(yDouble);
+    public void testPow() {
+        final Complex x = Complex.ofCartesian(3, 4);
+        final double yDouble = 5.0;
+        final Complex yComplex = Complex.ofReal(yDouble);
         Assertions.assertEquals(x.pow(yComplex), x.pow(yDouble));
     }
 
     @Test
-    public void testScalarPowNanBase() {
-        Complex x = NAN;
-        double yDouble = 5.0;
-        Complex yComplex = Complex.ofReal(yDouble);
-        Assertions.assertEquals(x.pow(yComplex), x.pow(yDouble));
+    public void testPowComplexZeroBase() {
+        final double x = Double.MIN_VALUE;
+        assertPowComplexZeroBase(0, 0, NAN);
+        assertPowComplexZeroBase(0, x, NAN);
+        assertPowComplexZeroBase(x, x, NAN);
+        assertPowComplexZeroBase(x, 0, Complex.ZERO);
+    }
+
+    private static void assertPowComplexZeroBase(double re, double im, Complex expected) {
+        final Complex z = Complex.ofCartesian(re, im);
+        final Complex c = Complex.ZERO.pow(z);
+        Assertions.assertEquals(expected, c);
     }
 
     @Test
-    public void testScalarPowZeroBaseZeroExponent() {
-        Complex x = Complex.ZERO;
-        double yDouble = 0;
-        Assertions.assertEquals(NAN, x.pow(yDouble));
-        Complex yComplex = Complex.ofReal(yDouble);
-        Assertions.assertEquals(NAN, x.pow(yComplex));
+    public void testPowScalarZeroBase() {
+        final double x = Double.MIN_VALUE;
+        assertPowScalarZeroBase(0, NAN);
+        assertPowScalarZeroBase(x, Complex.ZERO);
     }
+
+    private static void assertPowScalarZeroBase(double exp, Complex expected) {
+        final Complex c = Complex.ZERO.pow(exp);
+        Assertions.assertEquals(expected, c);
+    }
+
     @Test
-    public void testScalarPowZeroBasePositiveExponent() {
-        Complex x = Complex.ZERO;
-        double yDouble = Double.MIN_VALUE;
-        Assertions.assertEquals(Complex.ZERO, x.pow(yDouble));
-        Complex yComplex = Complex.ofReal(yDouble);
-        Assertions.assertEquals(Complex.ZERO, x.pow(yComplex));
+    public void testPowNanBase() {
+        final Complex x = NAN;
+        final double yDouble = 5.0;
+        final Complex yComplex = Complex.ofReal(yDouble);
+        Assertions.assertEquals(x.pow(yComplex), x.pow(yDouble));
     }
 
     @Test
-    public void testScalarPowNanExponent() {
-        Complex x = Complex.ofCartesian(3, 4);
-        double yDouble = Double.NaN;
-        Complex yComplex = Complex.ofReal(yDouble);
+    public void testPowNanExponent() {
+        final Complex x = Complex.ofCartesian(3, 4);
+        final double yDouble = Double.NaN;
+        final Complex yComplex = Complex.ofReal(yDouble);
         Assertions.assertEquals(x.pow(yComplex), x.pow(yDouble));
     }
+
     @Test
     public void testSqrtPolar() {
         final double tol = 1e-12;
@@ -619,13 +728,20 @@ public class ComplexTest {
             double theta = 0;
             for (int j = 0; j < 11; j++) {
                 theta += pi / 12;
-                Complex z = Complex.ofPolar(r, theta);
-                Complex sqrtz = Complex.ofPolar(Math.sqrt(r), theta / 2);
+                final Complex z = Complex.ofPolar(r, theta);
+                final Complex sqrtz = Complex.ofPolar(Math.sqrt(r), theta / 2);
                 TestUtils.assertEquals(sqrtz, z.sqrt(), tol);
             }
         }
     }
 
+    @Test
+    public void testZerothRootThrows() {
+        final Complex c = Complex.ofCartesian(1, 1);
+        Assertions.assertThrows(IllegalArgumentException.class, () -> c.nthRoot(0),
+            "zeroth root should not be allowed");
+    }
+
     /**
      * Test: computing <b>third roots</b> of z.
      * <pre>
@@ -640,9 +756,9 @@ public class ComplexTest {
     @Test
     public void testNthRootNormalThirdRoot() {
         // The complex number we want to compute all third-roots for.
-        Complex z = Complex.ofCartesian(-2,2);
+        final Complex z = Complex.ofCartesian(-2, 2);
         // The List holding all third roots
-        Complex[] thirdRootsOfZ = z.nthRoot(3).toArray(new Complex[0]);
+        final Complex[] thirdRootsOfZ = z.nthRoot(3).toArray(new Complex[0]);
         // Returned Collection must not be empty!
         Assertions.assertEquals(3, thirdRootsOfZ.length);
         // test z_0
@@ -656,7 +772,6 @@ public class ComplexTest {
         Assertions.assertEquals(-1.3660254037844384,  thirdRootsOfZ[2].getImaginary(), 1.0e-5);
     }
 
-
     /**
      * Test: computing <b>fourth roots</b> of z.
      * <pre>
@@ -672,9 +787,9 @@ public class ComplexTest {
     @Test
     public void testNthRootNormalFourthRoot() {
         // The complex number we want to compute all third-roots for.
-        Complex z = Complex.ofCartesian(5,-2);
+        final Complex z = Complex.ofCartesian(5, -2);
         // The List holding all fourth roots
-        Complex[] fourthRootsOfZ = z.nthRoot(4).toArray(new Complex[0]);
+        final Complex[] fourthRootsOfZ = z.nthRoot(4).toArray(new Complex[0]);
         // Returned Collection must not be empty!
         Assertions.assertEquals(4, fourthRootsOfZ.length);
         // test z_0
@@ -706,9 +821,9 @@ public class ComplexTest {
     public void testNthRootCornercaseThirdRootImaginaryPartEmpty() {
         // The number 8 has three third roots. One we all already know is the number 2.
         // But there are two more complex roots.
-        Complex z = Complex.ofCartesian(8,0);
+        final Complex z = Complex.ofCartesian(8, 0);
         // The List holding all third roots
-        Complex[] thirdRootsOfZ = z.nthRoot(3).toArray(new Complex[0]);
+        final Complex[] thirdRootsOfZ = z.nthRoot(3).toArray(new Complex[0]);
         // Returned Collection must not be empty!
         Assertions.assertEquals(3, thirdRootsOfZ.length);
         // test z_0
@@ -737,9 +852,9 @@ public class ComplexTest {
     @Test
     public void testNthRootCornercaseThirdRootRealPartZero() {
         // complex number with only imaginary part
-        Complex z = Complex.ofCartesian(0,2);
+        final Complex z = Complex.ofCartesian(0, 2);
         // The List holding all third roots
-        Complex[] thirdRootsOfZ = z.nthRoot(3).toArray(new Complex[0]);
+        final Complex[] thirdRootsOfZ = z.nthRoot(3).toArray(new Complex[0]);
         // Returned Collection must not be empty!
         Assertions.assertEquals(3, thirdRootsOfZ.length);
         // test z_0
@@ -771,13 +886,13 @@ public class ComplexTest {
     @Test
     public void testNthRootNegativeArg() {
         // The complex number we want to compute all third-roots for.
-        Complex z = Complex.ofCartesian(1, 0);
+        final Complex z = Complex.ofCartesian(1, 0);
         // The List holding all fourth roots
         Complex[] fourthRootsOfZ = z.nthRoot(4).toArray(new Complex[0]);
         // test z_0
         Assertions.assertEquals(1,     fourthRootsOfZ[0].getReal(),      1.0e-5);
         Assertions.assertEquals(0,   fourthRootsOfZ[0].getImaginary(), 1.0e-5);
-//         test z_1
+        // test z_1
         Assertions.assertEquals(0,    fourthRootsOfZ[1].getReal(),      1.0e-5);
         Assertions.assertEquals(1,     fourthRootsOfZ[1].getImaginary(), 1.0e-5);
         // test z_2
@@ -791,7 +906,7 @@ public class ComplexTest {
         // test z_0
         Assertions.assertEquals(1,     fourthRootsOfZ[0].getReal(),      1.0e-5);
         Assertions.assertEquals(0,   fourthRootsOfZ[0].getImaginary(), 1.0e-5);
-//         test z_1
+        // test z_1
         Assertions.assertEquals(0,    fourthRootsOfZ[1].getReal(),      1.0e-5);
         Assertions.assertEquals(-1,     fourthRootsOfZ[1].getImaginary(), 1.0e-5);
         // test z_2
@@ -808,9 +923,9 @@ public class ComplexTest {
         final Complex z = Complex.ofReal(Double.NaN);
         final List<Complex> r = z.nthRoot(n);
         Assertions.assertEquals(n, r.size());
-        for (Complex c : r) {
-            Assertions.assertTrue(Double.isNaN(c.real()));
-            Assertions.assertTrue(Double.isNaN(c.imag()));
+        for (final Complex c : r) {
+            Assertions.assertTrue(Double.isNaN(c.getReal()));
+            Assertions.assertTrue(Double.isNaN(c.getImaginary()));
         }
     }
     @Test
@@ -827,29 +942,28 @@ public class ComplexTest {
     @Test
     public void testGetArgument() {
         Complex z = Complex.ofCartesian(1, 0);
-        Assertions.assertEquals(0.0, z.getArgument(), 1.0e-12);
+        assertGetArgument(0.0, z, 1.0e-12);
 
         z = Complex.ofCartesian(1, 1);
-        Assertions.assertEquals(Math.PI/4, z.getArgument(), 1.0e-12);
+        assertGetArgument(Math.PI / 4, z, 1.0e-12);
 
         z = Complex.ofCartesian(0, 1);
-        Assertions.assertEquals(Math.PI/2, z.getArgument(), 1.0e-12);
+        assertGetArgument(Math.PI / 2, z, 1.0e-12);
 
         z = Complex.ofCartesian(-1, 1);
-        Assertions.assertEquals(3 * Math.PI/4, z.getArgument(), 1.0e-12);
+        assertGetArgument(3 * Math.PI / 4, z, 1.0e-12);
 
         z = Complex.ofCartesian(-1, 0);
-        Assertions.assertEquals(Math.PI, z.getArgument(), 1.0e-12);
+        assertGetArgument(Math.PI, z, 1.0e-12);
 
         z = Complex.ofCartesian(-1, -1);
-        Assertions.assertEquals(-3 * Math.PI/4, z.getArgument(), 1.0e-12);
+        assertGetArgument(-3 * Math.PI / 4, z, 1.0e-12);
 
         z = Complex.ofCartesian(0, -1);
-        Assertions.assertEquals(-Math.PI/2, z.getArgument(), 1.0e-12);
+        assertGetArgument(-Math.PI / 2, z, 1.0e-12);
 
         z = Complex.ofCartesian(1, -1);
-        Assertions.assertEquals(-Math.PI/4, z.getArgument(), 1.0e-12);
-
+        assertGetArgument(-Math.PI / 4, z, 1.0e-12);
     }
 
     /**
@@ -857,14 +971,14 @@ public class ComplexTest {
      */
     @Test
     public void testGetArgumentInf() {
-        Assertions.assertEquals(Math.PI/4, infInf.getArgument(), 1.0e-12);
-        Assertions.assertEquals(Math.PI/2, oneInf.getArgument(), 1.0e-12);
-        Assertions.assertEquals(0.0, infOne.getArgument(), 1.0e-12);
-        Assertions.assertEquals(Math.PI/2, zeroInf.getArgument(), 1.0e-12);
-        Assertions.assertEquals(0.0, infZero.getArgument(), 1.0e-12);
-        Assertions.assertEquals(Math.PI, negInfOne.getArgument(), 1.0e-12);
-        Assertions.assertEquals(-3.0*Math.PI/4, negInfNegInf.getArgument(), 1.0e-12);
-        Assertions.assertEquals(-Math.PI/2, oneNegInf.getArgument(), 1.0e-12);
+        assertGetArgument(Math.PI / 4, infInf, 1.0e-12);
+        assertGetArgument(Math.PI / 2, oneInf, 1.0e-12);
+        assertGetArgument(0.0, infOne, 1.0e-12);
+        assertGetArgument(Math.PI / 2, zeroInf, 1.0e-12);
+        assertGetArgument(0.0, infZero, 1.0e-12);
+        assertGetArgument(Math.PI, negInfOne, 1.0e-12);
+        assertGetArgument(-3.0 * Math.PI / 4, negInfNegInf, 1.0e-12);
+        assertGetArgument(-Math.PI / 2, oneNegInf, 1.0e-12);
     }
 
     /**
@@ -872,9 +986,15 @@ public class ComplexTest {
      */
     @Test
     public void testGetArgumentNaN() {
-        Assertions.assertTrue(Double.isNaN(nanZero.getArgument()));
-        Assertions.assertTrue(Double.isNaN(zeroNan.getArgument()));
-        Assertions.assertTrue(Double.isNaN(NAN.getArgument()));
+        assertGetArgument(Double.NaN, nanZero, 0);
+        assertGetArgument(Double.NaN, zeroNan, 0);
+        assertGetArgument(Double.NaN, NAN, 0);
+    }
+
+    private static void assertGetArgument(double expected, Complex complex, double delta) {
+        final double actual = complex.getArgument();
+        Assertions.assertEquals(expected, actual, delta);
+        Assertions.assertEquals(actual, complex.arg(), delta);
     }
 
     @Test
@@ -896,35 +1016,37 @@ public class ComplexTest {
         final String re = "1.234";
         final String im = "5.678";
         Assertions.assertThrows(IllegalArgumentException.class,
-                () -> Complex.parse( re + "," + im + ")")
+            () -> Complex.parse(re + "," + im + ")")
         );
-
     }
+
     @Test
     public void testParseWrongEnd() {
         final String re = "1.234";
         final String im = "5.678";
         Assertions.assertThrows(IllegalArgumentException.class,
-                () -> Complex.parse("(" + re + "," + im)
+            () -> Complex.parse("(" + re + "," + im)
         );
-
     }
+
     @Test
     public void testParseMissingSeparator() {
         final String re = "1.234";
         final String im = "5.678";
         Assertions.assertThrows(IllegalArgumentException.class,
-                () -> Complex.parse("(" + re + " " + im + ")")
+            () -> Complex.parse("(" + re + " " + im + ")")
         );
     }
+
     @Test
     public void testParseInvalidRe() {
         final String re = "I.234";
         final String im = "5.678";
         Assertions.assertThrows(IllegalArgumentException.class,
-                () -> Complex.parse("(" + re + "," + im + ")")
+            () -> Complex.parse("(" + re + "," + im + ")")
         );
     }
+
     @Test
     public void testParseInvalidIm() {
         final String re = "1.234";
@@ -941,4 +1063,37 @@ public class ComplexTest {
         final String str = "(  " + re + "  , " + im + "     )";
         Assertions.assertEquals(Complex.ofCartesian(re, im), Complex.parse(str));
     }
+
+    @Test
+    public void testCGrammar() {
+        final UniformRandomProvider rng = RandomSource.create(RandomSource.SPLIT_MIX_64);
+        for (int i = 0; i < 10; i++) {
+            final Complex z = Complex.ofCartesian(rng.nextDouble(), rng.nextDouble());
+            Assertions.assertEquals(z.getReal(), z.real(), "real");
+            Assertions.assertEquals(z.getImaginary(), z.imag(), "imag");
+            Assertions.assertEquals(z.conjugate(), z.conj(), "conj");
+            Assertions.assertEquals(z.getArgument(), z.arg(), "arg");
+        }
+    }
+
+    @Test
+    public void testLog10() {
+        final double ln10 = Math.log(10.0);
+        final UniformRandomProvider rng = RandomSource.create(RandomSource.SPLIT_MIX_64);
+        for (int i = 0; i < 10; i++) {
+            final Complex z = Complex.ofCartesian(rng.nextDouble(), rng.nextDouble());
+            final Complex lnz = z.log();
+            final Complex log10z = z.log10();
+            Assertions.assertEquals(lnz.getReal() / ln10, log10z.getReal(), "real");
+            Assertions.assertEquals(lnz.getImaginary(), log10z.getImaginary(), "imag");
+        }
+    }
+
+    @Test
+    @Disabled("Required if not implemented in terms of tanh")
+    public void testTan() {
+        // Check the conditions on the imaginary component that create special results.
+        TestUtils.assertEquals(Complex.ONE, Complex.ofCartesian(0, 25).tan(), 0);
+        TestUtils.assertEquals(Complex.ofCartesian(0, -1), Complex.ofCartesian(0, -25).tan(), 0);
+    }
 }
diff --git a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/TestUtils.java b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/TestUtils.java
index 3fae6c5..17d7ac8 100644
--- a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/TestUtils.java
+++ b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/TestUtils.java
@@ -23,7 +23,6 @@ import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 
-import org.apache.commons.numbers.complex.Complex;
 import org.apache.commons.numbers.core.Precision;
 
 import org.junit.jupiter.api.Assertions;
@@ -32,7 +31,7 @@ import org.junit.jupiter.api.Assertions;
  * Test utilities.
  * TODO: Cleanup (remove unused and obsolete methods).
  */
-public class TestUtils {
+public final class TestUtils {
     /**
      * Collection of static methods used in math unit tests.
      */
@@ -41,8 +40,12 @@ public class TestUtils {
     }
 
     /**
-     * Verifies that real and imaginary parts of the two complex arguments
-     * are exactly the same.  Also ensures that NaN / infinite components match.
+     * Verifies that real and imaginary parts of the two complex arguments are exactly the
+     * same as defined by {@link Double#compare(double, double)}. Also ensures that NaN /
+     * infinite components match.
+     *
+     * @param expected the expected value
+     * @param actual the actual value
      */
     public static void assertSame(Complex expected, Complex actual) {
         Assertions.assertEquals(expected.getReal(), actual.getReal());
@@ -50,8 +53,12 @@ public class TestUtils {
     }
 
     /**
-     * Verifies that real and imaginary parts of the two complex arguments
-     * differ by at most delta.  Also ensures that NaN / infinite components match.
+     * Verifies that real and imaginary parts of the two complex arguments differ by at
+     * most delta. Also ensures that NaN / infinite components match.
+     *
+     * @param expected the expected value
+     * @param actual the actual value
+     * @param delta the delta
      */
     public static void assertEquals(Complex expected, Complex actual, double delta) {
         Assertions.assertEquals(expected.getReal(), actual.getReal(), delta);
@@ -68,17 +75,17 @@ public class TestUtils {
     public static Object serializeAndRecover(Object o) {
         try {
             // serialize the Object
-            ByteArrayOutputStream bos = new ByteArrayOutputStream();
-            ObjectOutputStream so = new ObjectOutputStream(bos);
+            final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            final ObjectOutputStream so = new ObjectOutputStream(bos);
             so.writeObject(o);
 
             // deserialize the Object
-            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
-            ObjectInputStream si = new ObjectInputStream(bis);
+            final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+            final ObjectInputStream si = new ObjectInputStream(bis);
             return si.readObject();
-        } catch (IOException ioe) {
+        } catch (final IOException ioe) {
             return null;
-        } catch (ClassNotFoundException cnfe) {
+        } catch (final ClassNotFoundException cnfe) {
             return null;
         }
     }
@@ -90,7 +97,7 @@ public class TestUtils {
      * @param object  the object to serialize and recover
      */
     public static void checkSerializedEquality(Object object) {
-        Object object2 = serializeAndRecover(object);
+        final Object object2 = serializeAndRecover(object);
         Assertions.assertEquals(object, object2, "Equals check");
         Assertions.assertEquals(object.hashCode(), object2.hashCode(), "HashCode check");
     }
@@ -130,7 +137,7 @@ public class TestUtils {
         } else if (expected == 0.0) {
             Assertions.assertEquals(actual, expected, relativeError, msg);
         } else {
-            double absError = Math.abs(expected) * relativeError;
+            final double absError = Math.abs(expected) * relativeError;
             Assertions.assertEquals(expected, actual, absError, msg);
         }
     }
@@ -145,7 +152,7 @@ public class TestUtils {
      */
     public static void assertContains(String msg, Complex[] values,
                                       Complex z, double epsilon) {
-        for (Complex value : values) {
+        for (final Complex value : values) {
             if (Precision.equals(value.getReal(), z.getReal(), epsilon) &&
                 Precision.equals(value.getImaginary(), z.getImaginary(), epsilon)) {
                 return;
@@ -176,7 +183,7 @@ public class TestUtils {
      */
     public static void assertContains(String msg, double[] values,
             double x, double epsilon) {
-        for (double value : values) {
+        for (final double value : values) {
             if (Precision.equals(value, x, epsilon)) {
                 return;
             }
@@ -193,12 +200,12 @@ public class TestUtils {
      */
     public static void assertContains(double[] values, double x,
             double epsilon) {
-       assertContains(null, values, x, epsilon);
+        assertContains(null, values, x, epsilon);
     }
 
     /** verifies that two arrays are close (sup norm) */
     public static void assertEquals(String msg, Complex[] expected, Complex[] observed, double tolerance) {
-        StringBuilder out = new StringBuilder(msg);
+        final StringBuilder out = new StringBuilder(msg);
         if (expected.length != observed.length) {
             out.append("\n Arrays not same length. \n");
             out.append("expected has length ");
@@ -208,7 +215,7 @@ public class TestUtils {
             Assertions.fail(out.toString());
         }
         boolean failure = false;
-        for (int i=0; i < expected.length; i++) {
+        for (int i = 0; i < expected.length; i++) {
             if (!Precision.equalsIncludingNaN(expected[i].getReal(), observed[i].getReal(), tolerance)) {
                 failure = true;
                 out.append("\n Real elements at index ");
@@ -265,8 +272,8 @@ public class TestUtils {
             }
         }
         if (positiveMassCount < densityValues.length) {
-            int[] newPoints = new int[positiveMassCount];
-            double[] newValues = new double[positiveMassCount];
+            final int[] newPoints = new int[positiveMassCount];
+            final double[] newValues = new double[positiveMassCount];
             int j = 0;
             for (int i = 0; i < densityValues.length; i++) {
                 if (densityValues[i] > 0) {
@@ -275,8 +282,8 @@ public class TestUtils {
                     j++;
                 }
             }
-            System.arraycopy(newPoints,0,densityPoints,0,positiveMassCount);
-            System.arraycopy(newValues,0,densityValues,0,positiveMassCount);
+            System.arraycopy(newPoints, 0, densityPoints, 0, positiveMassCount);
+            System.arraycopy(newValues, 0, densityValues, 0, positiveMassCount);
         }
         return positiveMassCount;
     }