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/12/21 17:16:33 UTC

[commons-numbers] branch master updated (32d8fc1 -> ceb6269)

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

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


    from 32d8fc1  Overflow test for pow()
     new 940705a  Changed ofPolar to not throw IllegalArgumentException.
     new 5fad5e2  Added norm method that is part of the C++ standard for complex.
     new ceb6269  Test abs() and arg() return the input to ofPolar constructor.

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../apache/commons/numbers/complex/Complex.java    | 89 +++++++++++++++++-----
 .../commons/numbers/complex/ComplexTest.java       | 59 +++++++++++++-
 2 files changed, 128 insertions(+), 20 deletions(-)


[commons-numbers] 02/03: Added norm method that is part of the C++ standard for complex.

Posted by ah...@apache.org.
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 5fad5e285c6498d3747ebd75f98557b6a9324fcc
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Sat Dec 21 17:04:21 2019 +0000

    Added norm method that is part of the C++ standard for complex.
    
    This returns the same value as squared abs().
---
 .../apache/commons/numbers/complex/Complex.java    | 26 ++++++++++++++++++++++
 .../commons/numbers/complex/ComplexTest.java       | 19 ++++++++++++++++
 2 files changed, 45 insertions(+)

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 a6f8da4..23c79a4 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
@@ -435,6 +435,7 @@ public final class Complex implements Serializable  {
      * @see #isInfinite()
      * @see #isNaN()
      * @see Math#hypot(double, double)
+     * @see <a href="http://mathworld.wolfram.com/ComplexModulus.html">Complex modulus</a>
      */
     public double abs() {
         // Delegate
@@ -457,6 +458,31 @@ public final class Complex implements Serializable  {
     }
 
     /**
+     * Return the squared norm value of this complex number. This is also called the absolute
+     * square.
+     * <pre>norm(a + b i) = a^2 + b^2</pre>
+     *
+     * <p>If either component is infinite then the result is positive infinity. If either
+     * component is NaN and this is not {@link #isInfinite() infinite} then the result is NaN.
+     *
+     * <p>This method will return the square of {@link #abs()}. It can be used as a faster
+     * alternative for ranking by magnitude although overflow to infinity will create equal
+     * ranking for values that may be still distinguished by {@code abs()}.
+     *
+     * @return the square norm value.
+     * @see #isInfinite()
+     * @see #isNaN()
+     * @see #abs()
+     * @see <a href="http://mathworld.wolfram.com/AbsoluteSquare.html">Absolute square</a>
+     */
+    public double norm() {
+        if (isInfinite()) {
+            return Double.POSITIVE_INFINITY;
+        }
+        return real * real + imaginary * imaginary;
+    }
+
+    /**
      * Returns a {@code Complex} whose value is {@code (this + addend)}.
      * Implements the formula:
      * <pre>
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 13eb77c..7d6770d 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
@@ -224,6 +224,25 @@ public class ComplexTest {
     }
 
     @Test
+    public void testNorm() {
+        final Complex z = Complex.ofCartesian(3.0, 4.0);
+        Assertions.assertEquals(25.0, z.norm());
+    }
+
+    @Test
+    public void testNormNaN() {
+        // The result is NaN if either argument is NaN and the other is not infinite
+        Assertions.assertEquals(nan, NAN.norm());
+        Assertions.assertEquals(nan, Complex.ofCartesian(3.0, nan).norm());
+        Assertions.assertEquals(nan, Complex.ofCartesian(nan, 3.0).norm());
+        // The result is positive infinite if either argument is infinite
+        Assertions.assertEquals(inf, Complex.ofCartesian(inf, nan).norm());
+        Assertions.assertEquals(inf, Complex.ofCartesian(-inf, nan).norm());
+        Assertions.assertEquals(inf, Complex.ofCartesian(nan, inf).norm());
+        Assertions.assertEquals(inf, Complex.ofCartesian(nan, -inf).norm());
+    }
+
+    @Test
     public void testAdd() {
         final Complex x = Complex.ofCartesian(3.0, 4.0);
         final Complex y = Complex.ofCartesian(5.0, 6.0);


[commons-numbers] 03/03: Test abs() and arg() return the input to ofPolar constructor.

Posted by ah...@apache.org.
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 ceb62698d95a6b6a562a896c8ed8e82e72f1e411
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Sat Dec 21 17:16:29 2019 +0000

    Test abs() and arg() return the input to ofPolar constructor.
---
 .../org/apache/commons/numbers/complex/ComplexTest.java   | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

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 7d6770d..82c2cee 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
@@ -123,6 +123,21 @@ public class ComplexTest {
     }
 
     @Test
+    public void testPolarConstructorAbsArg() {
+        // The test should work with any seed but use a fixed seed to avoid build instability.
+        final UniformRandomProvider rng = RandomSource.create(RandomSource.SPLIT_MIX_64, 678678638L);
+        for (int i = 0; i < 10; i++) {
+            final double rho = rng.nextDouble();
+            // Range (pi, pi]: lower exclusive, upper inclusive
+            final double theta = pi - rng.nextDouble() * 2 * pi;
+            final Complex z = Complex.ofPolar(rho, theta);
+            // Match within 1 ULP
+            Assertions.assertEquals(rho, z.abs(), Math.ulp(rho));
+            Assertions.assertEquals(theta, z.arg(), Math.ulp(theta));
+        }
+    }
+
+    @Test
     public void testCisConstructor() {
         final double x = 0.12345;
         final Complex z = Complex.ofCis(x);


[commons-numbers] 01/03: Changed ofPolar to not throw IllegalArgumentException.

Posted by ah...@apache.org.
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 940705ae6efd2e7165993a4170357ce1425a6442
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Sat Dec 21 16:55:48 2019 +0000

    Changed ofPolar to not throw IllegalArgumentException.
    
    Method will return NaN for input arguments that are not allowed.
    
    rho must be non-negative and non-nan.
    
    theta must be finite.
    
    This is in compliance with C++ behaviour.
---
 .../apache/commons/numbers/complex/Complex.java    | 63 +++++++++++++++-------
 .../commons/numbers/complex/ComplexTest.java       | 25 ++++++++-
 2 files changed, 68 insertions(+), 20 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 a126040..a6f8da4 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
@@ -196,46 +196,73 @@ public final class Complex implements Serializable  {
      *
      * @param real Real part.
      * @param imaginary Imaginary part.
-     * @return {@code Complex} object
+     * @return {@code Complex} number
      */
     public static Complex ofCartesian(double real, double imaginary) {
         return new Complex(real, imaginary);
     }
 
     /**
-     * Creates a Complex from its polar representation.
+     * Creates a complex number from its polar representation using modulus {@code rho}
+     * and phase angle {@code theta}.
+     * <pre>
+     *  x = rho * cos(theta)
+     *  y = rho * sin(theta)
+     * </pre>
+     *
+     * <p>Requires that {@code rho} is non-negative and non-NaN and {@code theta} is finite;
+     * otherwise returns a complex with NaN real and imaginary parts. A value of {@code -0.0} is
+     * considered negative and an invalid modulus.
+     *
+     * <p>A non-NaN complex number constructed using this method will satisfy the following
+     * to within floating-point error:</p>
+     * <pre>
+     *  Complex.ofPolar(rho, theta).abs() == rho
+     *  Complex.ofPolar(rho, theta).arg() == theta; theta in (\(-\pi\), \(\pi\)]
+     * </pre>
      *
-     * <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.</p>
+     * <p>If {@code rho} is infinite then the resulting parts may be infinite or NaN
+     * following the rules for double arithmetic.</p>
      *
      * <pre>
      * Examples:
      * {@code
-     * ofPolar(INFINITY, \(\pi\)) = INFINITY + INFINITY i
+     * ofPolar(-0.0, 0.0) = NaN + NaN i
+     * ofPolar(0.0, 0.0) = 0.0 + 0.0 i
+     * ofPolar(1.0, 0.0) = 1.0 + 0.0 i
+     * ofPolar(1.0, \(\pi\)) = -1.0 + sin(\(\pi\)) i
+     * ofPolar(INFINITY, \(\pi\)) = -INFINITY + INFINITY i
      * ofPolar(INFINITY, 0) = INFINITY + NaN i
      * ofPolar(INFINITY, \(-\frac{\pi}{4}\)) = INFINITY - INFINITY i
      * ofPolar(INFINITY, \(5\frac{\pi}{4}\)) = -INFINITY - INFINITY i }
      * </pre>
      *
-     * @param r the modulus of the complex number to create
+     * @param rho 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
+     * @return {@code Complex} number
+     * @see <a href="http://mathworld.wolfram.com/PolarCoordinates.html">Polar Coordinates</a>
      */
-    public static Complex ofPolar(double r, double theta) {
-        if (r <= 0) {
-            throw new IllegalArgumentException("Non-positive polar modulus argument: " + r);
+    public static Complex ofPolar(double rho, double theta) {
+        // Require finite theta and non-negative, non-nan rho
+        if (!Double.isFinite(theta) || negative(rho) || Double.isNaN(rho)) {
+            return NAN;
         }
-        return new Complex(r * Math.cos(theta), r * Math.sin(theta));
+        final double x = rho * Math.cos(theta);
+        final double y = rho * Math.sin(theta);
+        return new Complex(x, y);
     }
 
     /**
-     * For a real constructor argument x, returns a new Complex object c
-     * where {@code c = cos(x) + i sin (x)}.
+     * Create a complex cis number. This is also known as the complex exponential:
+     * <pre>
+     * <code>
+     *   cis(x) = e<sup>ix</sup> = cos(x) + i sin(x)
+     * </code>
+     * </pre>
      *
      * @param x {@code double} to build the cis number
-     * @return {@code Complex}
+     * @return {@code Complex} cis number
+     * @see <a href="http://mathworld.wolfram.com/Cis.html">Cis</a>
      */
     public static Complex ofCis(double x) {
         return new Complex(Math.cos(x), Math.sin(x));
@@ -264,7 +291,7 @@ public final class Complex implements Serializable  {
      * </pre>
      *
      * @param s String representation.
-     * @return an instance.
+     * @return {@code Complex} number
      * @throws NullPointerException if the string is null.
      * @throws NumberFormatException if the string does not contain a parsable complex number.
      * @see Double#parseDouble(String)
@@ -392,7 +419,7 @@ public final class Complex implements Serializable  {
     }
 
     /**
-     * Return the absolute value of this complex number. This is also called norm, modulus,
+     * Return the absolute value of this complex number. This is also called complex norm, modulus,
      * or magnitude.
      * <pre>abs(a + b i) = sqrt(a^2 + b^2)</pre>
      *
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 9d89490..13eb77c 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
@@ -97,8 +97,29 @@ public class ComplexTest {
         Assertions.assertEquals(r * y.getReal(), z.getReal());
         Assertions.assertEquals(r * y.getImaginary(), z.getImaginary());
 
-        Assertions.assertThrows(IllegalArgumentException.class, () -> Complex.ofPolar(-1, 0),
-            "negative modulus should not be allowed");
+        // Edge cases
+        // Non-finite theta
+        Assertions.assertEquals(NAN, Complex.ofPolar(1, -inf));
+        Assertions.assertEquals(NAN, Complex.ofPolar(1, inf));
+        Assertions.assertEquals(NAN, Complex.ofPolar(1, nan));
+        // Infinite rho is invalid when theta is NaN
+        // i.e. do not create an infinite complex such as (inf, nan)
+        Assertions.assertEquals(NAN, Complex.ofPolar(inf, nan));
+        // negative or NaN rho
+        Assertions.assertEquals(NAN, Complex.ofPolar(-inf, 1));
+        Assertions.assertEquals(NAN, Complex.ofPolar(-0.0, 1));
+        Assertions.assertEquals(NAN, Complex.ofPolar(nan, 1));
+
+        // Construction from infinity has values left to double arithmetic.
+        // Test the examples from the javadoc
+        Assertions.assertEquals(NAN, Complex.ofPolar(-0.0, 0.0));
+        Assertions.assertEquals(Complex.ofCartesian(0.0, 0.0), Complex.ofPolar(0.0, 0.0));
+        Assertions.assertEquals(Complex.ofCartesian(1.0, 0.0), Complex.ofPolar(1.0, 0.0));
+        Assertions.assertEquals(Complex.ofCartesian(-1.0, Math.sin(pi)), Complex.ofPolar(1.0, pi));
+        Assertions.assertEquals(Complex.ofCartesian(-inf, inf), Complex.ofPolar(inf, pi));
+        Assertions.assertEquals(Complex.ofCartesian(inf, nan), Complex.ofPolar(inf, 0.0));
+        Assertions.assertEquals(Complex.ofCartesian(inf, -inf), Complex.ofPolar(inf, -pi / 4));
+        Assertions.assertEquals(Complex.ofCartesian(-inf, -inf), Complex.ofPolar(inf, 5 * pi / 4));
     }
 
     @Test