You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by GitBox <gi...@apache.org> on 2022/07/26 09:39:04 UTC

[GitHub] [commons-numbers] aherbert commented on a diff in pull request #119: Numbers 188: refactored binary functions

aherbert commented on code in PR #119:
URL: https://github.com/apache/commons-numbers/pull/119#discussion_r929700456


##########
commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexBinaryOperator.java:
##########
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.numbers.complex;
+
+import java.util.Objects;
+
+/**
+ * Represents a binary operation on a Cartesian form of a complex number \( a + ib \)
+ * where \( a \) and \( b \) are real numbers represented as two {@code double}
+ * parts. The operation creates a complex number result; the result is supplied
+ * to a terminating consumer function which may return an object representation
+ * of the complex result.
+ *
+ * <p>This is a functional interface whose functional method is
+ * {@link #apply(double, double, double, double, ComplexSink)}.
+ *
+ * @param <R> The type of the complex result
+ * @since 1.1
+ */
+@FunctionalInterface
+public interface ComplexBinaryOperator<R> {
+
+    /**
+     * Represents an operator that accepts real and imaginary parts of a complex number and supplies the complex result to the provided consumer.
+     * @param real1 Real part \( a \) of the first complex number \( (a +ib) \).

Review Comment:
   `parts of two complex numbers`
   
   Add a blank line before the param tags. You can do the same in the other interface for consistency.
   



##########
commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexBinaryOperator.java:
##########
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.numbers.complex;
+
+import java.util.Objects;
+
+/**
+ * Represents a binary operation on a Cartesian form of a complex number \( a + ib \)
+ * where \( a \) and \( b \) are real numbers represented as two {@code double}
+ * parts. The operation creates a complex number result; the result is supplied
+ * to a terminating consumer function which may return an object representation
+ * of the complex result.
+ *
+ * <p>This is a functional interface whose functional method is
+ * {@link #apply(double, double, double, double, ComplexSink)}.
+ *
+ * @param <R> The type of the complex result
+ * @since 1.1
+ */
+@FunctionalInterface
+public interface ComplexBinaryOperator<R> {
+
+    /**
+     * Represents an operator that accepts real and imaginary parts of a complex number and supplies the complex result to the provided consumer.
+     * @param real1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param imaginary1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param real2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param imaginary2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param out Consumer for the complex result.
+     * @return the object returned by the provided consumer.
+     */
+    R apply(double real1, double imaginary1, double real2, double imaginary2, ComplexSink<R> out);
+
+    /**
+     * Returns a composed function that first applies this function to its input, and then applies the after function to the result.
+     * If evaluation of either function throws an exception, it is relayed to the caller of the composed function.
+     * @param after the function to apply after this function is applied
+     * @return a composed function that first applies this function and then applies the after function
+     */
+    default ComplexBinaryOperator<R> andThen(ComplexUnaryOperator<R> after) {

Review Comment:
   Not currently required 



##########
commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexFunctions.java:
##########
@@ -396,6 +399,255 @@ public static <R> R proj(double real, double imaginary, ComplexSink<R> action) {
         return action.apply(real, imaginary);
     }
 
+    /**
+     * Returns a {@code Object} whose value is {@code (real1 + real2, imaginary1 + imaginary2)}.
+     * Implements the formula:
+     *
+     * <p>\[ (a + i b) + (c + i d) = (a + c) + i (b + d) \]
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final added complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     * @see <a href="http://mathworld.wolfram.com/ComplexAddition.html">Complex Addition</a>
+     */
+    public static <R> R add(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        return action.apply(re1 + re2,
+            im1 + im2);
+    }
+
+    /**
+     * Returns a {@code Object} whose value is {@code (real1 - real2, imaginary1 - imaginary2)}.
+     * Implements the formula:
+     *
+     * <p>\[ (a + i b) - (c + i d) = (a - c) + i (b - d) \]
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final subtracted complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     * @see <a href="http://mathworld.wolfram.com/ComplexSubtraction.html">Complex Subtraction</a>
+     */
+    public static <R> R subtract(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        return action.apply(re1 - re2,
+            im1 - im2);

Review Comment:
   Indent



##########
commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexFunctions.java:
##########
@@ -396,6 +399,255 @@ public static <R> R proj(double real, double imaginary, ComplexSink<R> action) {
         return action.apply(real, imaginary);
     }
 
+    /**
+     * Returns a {@code Object} whose value is {@code (real1 + real2, imaginary1 + imaginary2)}.
+     * Implements the formula:
+     *
+     * <p>\[ (a + i b) + (c + i d) = (a + c) + i (b + d) \]
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final added complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     * @see <a href="http://mathworld.wolfram.com/ComplexAddition.html">Complex Addition</a>
+     */
+    public static <R> R add(double re1, double im1, double re2, double im2, ComplexSink<R> action) {

Review Comment:
   It may be very verbose but for consistency we should use `real1/2` and `imaginary1/2` as these are the names used for all the unary functions. This matches what you have put in the javadoc too.



##########
commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexFunctions.java:
##########
@@ -396,6 +399,255 @@ public static <R> R proj(double real, double imaginary, ComplexSink<R> action) {
         return action.apply(real, imaginary);
     }
 
+    /**
+     * Returns a {@code Object} whose value is {@code (real1 + real2, imaginary1 + imaginary2)}.
+     * Implements the formula:
+     *
+     * <p>\[ (a + i b) + (c + i d) = (a + c) + i (b + d) \]
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final added complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     * @see <a href="http://mathworld.wolfram.com/ComplexAddition.html">Complex Addition</a>
+     */
+    public static <R> R add(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        return action.apply(re1 + re2,
+            im1 + im2);

Review Comment:
   Indentation



##########
commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexFunctions.java:
##########
@@ -396,6 +399,255 @@ public static <R> R proj(double real, double imaginary, ComplexSink<R> action) {
         return action.apply(real, imaginary);
     }
 
+    /**
+     * Returns a {@code Object} whose value is {@code (real1 + real2, imaginary1 + imaginary2)}.
+     * Implements the formula:
+     *
+     * <p>\[ (a + i b) + (c + i d) = (a + c) + i (b + d) \]
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final added complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     * @see <a href="http://mathworld.wolfram.com/ComplexAddition.html">Complex Addition</a>
+     */
+    public static <R> R add(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        return action.apply(re1 + re2,
+            im1 + im2);
+    }
+
+    /**
+     * Returns a {@code Object} whose value is {@code (real1 - real2, imaginary1 - imaginary2)}.
+     * Implements the formula:
+     *
+     * <p>\[ (a + i b) - (c + i d) = (a - c) + i (b - d) \]
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final subtracted complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     * @see <a href="http://mathworld.wolfram.com/ComplexSubtraction.html">Complex Subtraction</a>
+     */
+    public static <R> R subtract(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        return action.apply(re1 - re2,
+            im1 - im2);
+    }
+
+    /**
+     * Returns a {@code Object} whose value is:

Review Comment:
   Wrong javadoc. Copy  from Complex which uses the MathJax formula.
   
   Note that the use of `<pre>` tags for formulas was only used on internal private methods. This can be rendered by an IDE allowing for example you to read the javadocs when hovering over a method.
   
   Public API javadoc should all use MathJax. This is rendered when creating the docs. See:
   ```
   mvn javadoc:javadoc
   open target/site/apidocs/index.html
   ```
   



##########
commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexFunctions.java:
##########
@@ -677,6 +929,48 @@ private static <R> R log(DoubleUnaryOperator log,
         return action.apply(re, arg(real, imaginary));
     }
 
+    /**
+     * Returns the complex power of the first complex number raised to the power of
+     * second complex number.
+     * Implements the formula:
+     *
+     * <p>\[ z^x = e^{x \ln(z)} \]
+     *
+     * <p>If the complex number is zero then this method returns zero if the second complex number is positive
+     * in the real component and zero in the imaginary component;
+     * otherwise it returns NaN + iNaN.
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the power of the complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     * @see #log(double, double, ComplexSink)
+     * @see #multiply(double, double, double, double, ComplexSink)
+     * @see #exp(double, double, ComplexSink)
+     * @see <a href="http://mathworld.wolfram.com/ComplexExponentiation.html">Complex exponentiation</a>
+     * @see <a href="http://functions.wolfram.com/ElementaryFunctions/Power/">Power</a>
+     */
+    public static <R> R pow(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        if (re1 == 0 &&
+            im1 == 0) {
+            // This value is zero. Test the other.
+            if (re2 > 0 &&
+                im2 == 0) {
+                // 0 raised to positive number is 0
+                return action.apply(0, 0);
+            }
+            // 0 raised to anything else is NaN
+            return action.apply(Double.NaN, Double.NaN);
+        }
+        final ComplexUnaryOperator<R> log = ComplexFunctions::log;

Review Comment:
   These declarations could be done in a static final variable. However we do not need to to use the `andThen` composition:
   ```Java
           return log(re1, im1, (x, y) -> {
               return multiply(x, y, re2, im2, (a, b) -> {
                   return exp(a, b, action);
               });
           });
   ```
   I am undecided which is preferred. However to avoid adding the `andThen` function just to support this composition I would use the explicit lambda code above.



##########
commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexFunctions.java:
##########
@@ -396,6 +399,255 @@ public static <R> R proj(double real, double imaginary, ComplexSink<R> action) {
         return action.apply(real, imaginary);
     }
 
+    /**
+     * Returns a {@code Object} whose value is {@code (real1 + real2, imaginary1 + imaginary2)}.
+     * Implements the formula:
+     *
+     * <p>\[ (a + i b) + (c + i d) = (a + c) + i (b + d) \]
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final added complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     * @see <a href="http://mathworld.wolfram.com/ComplexAddition.html">Complex Addition</a>
+     */
+    public static <R> R add(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        return action.apply(re1 + re2,
+            im1 + im2);
+    }
+
+    /**
+     * Returns a {@code Object} whose value is {@code (real1 - real2, imaginary1 - imaginary2)}.
+     * Implements the formula:
+     *
+     * <p>\[ (a + i b) - (c + i d) = (a - c) + i (b - d) \]
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final subtracted complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     * @see <a href="http://mathworld.wolfram.com/ComplexSubtraction.html">Complex Subtraction</a>
+     */
+    public static <R> R subtract(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        return action.apply(re1 - re2,
+            im1 - im2);
+    }
+
+    /**
+     * Returns a {@code Object} whose value is:
+     * <pre>
+     *  (a + i b)(c + i d) = (ac - bd) + i (ad + bc)</pre>
+     *
+     * <p>Recalculates to recover infinities as specified in C99 standard G.5.1.
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final multiplied complex number.

Review Comment:
   Consumer for the multiplication result.



##########
commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexFunctions.java:
##########
@@ -2563,4 +2946,22 @@ private static double changeSign(double magnitude, double signedValue) {
     private static boolean inRegion(double x, double y, double min, double max) {
         return x < max && x > min && y < max && y > min;
     }
+
+    /**
+     * Returns a composed BinaryOperator that first applies this function to its first binary input,
+     * and then applies the result and the second binary input to the after BinaryOperator to produce the result.
+     * If evaluation of either function throws an exception, it is relayed to the caller of the composed function.
+     *
+     * @param before the function as to which the apply function is applied
+     * @param after the function to apply after this function is applied
+     * @param <R> generic
+     * @return a composed function that first applies this function and then applies the after function
+     */
+    private static <R> ComplexBinaryOperator<R> thenApplyBinaryOperator(ComplexUnaryOperator<R> before,

Review Comment:
   This method is not used.



##########
commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexFunctions.java:
##########
@@ -396,6 +399,255 @@ public static <R> R proj(double real, double imaginary, ComplexSink<R> action) {
         return action.apply(real, imaginary);
     }
 
+    /**
+     * Returns a {@code Object} whose value is {@code (real1 + real2, imaginary1 + imaginary2)}.
+     * Implements the formula:
+     *
+     * <p>\[ (a + i b) + (c + i d) = (a + c) + i (b + d) \]
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final added complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     * @see <a href="http://mathworld.wolfram.com/ComplexAddition.html">Complex Addition</a>
+     */
+    public static <R> R add(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        return action.apply(re1 + re2,
+            im1 + im2);
+    }
+
+    /**
+     * Returns a {@code Object} whose value is {@code (real1 - real2, imaginary1 - imaginary2)}.
+     * Implements the formula:
+     *
+     * <p>\[ (a + i b) - (c + i d) = (a - c) + i (b - d) \]
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final subtracted complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     * @see <a href="http://mathworld.wolfram.com/ComplexSubtraction.html">Complex Subtraction</a>
+     */
+    public static <R> R subtract(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        return action.apply(re1 - re2,
+            im1 - im2);
+    }
+
+    /**
+     * Returns a {@code Object} whose value is:
+     * <pre>
+     *  (a + i b)(c + i d) = (ac - bd) + i (ad + bc)</pre>
+     *
+     * <p>Recalculates to recover infinities as specified in C99 standard G.5.1.
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final multiplied complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     */
+    public static <R> R multiply(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        double a = re1;
+        double b = im1;
+        double c = re2;
+        double d = im2;
+        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;
+
+        // --------------
+        // NaN can occur if:
+        // - any of (a,b,c,d) are NaN (for NaN or Infinite complex numbers)
+        // - a multiplication of infinity by zero (ac,bd,ad,bc).
+        // - a subtraction of infinity from infinity (e.g. ac - bd)
+        //   Note that (ac,bd,ad,bc) can be infinite due to overflow.
+        //
+        // Detect a NaN result and perform correction.
+        //
+        // Modification from the listing in ISO C99 G.5.1 (6)
+        // Do not correct infinity multiplied by zero. This is left as NaN.
+        // --------------
+
+        if (Double.isNaN(x) && Double.isNaN(y)) {
+            // Recover infinities that computed as NaN+iNaN ...
+            boolean recalc = false;
+            if ((Double.isInfinite(a) || Double.isInfinite(b)) &&
+                isNotZero(c, d)) {
+                // This complex is infinite.
+                // "Box" the infinity and change NaNs in the other factor to 0.
+                a = boxInfinity(a);
+                b = boxInfinity(b);
+                c = changeNaNtoZero(c);
+                d = changeNaNtoZero(d);
+                recalc = true;
+            }
+            if ((Double.isInfinite(c) || Double.isInfinite(d)) &&
+                isNotZero(a, b)) {
+                // The other complex is infinite.
+                // "Box" the infinity and change NaNs in the other factor to 0.
+                c = boxInfinity(c);
+                d = boxInfinity(d);
+                a = changeNaNtoZero(a);
+                b = changeNaNtoZero(b);
+                recalc = true;
+            }
+            if (!recalc && (Double.isInfinite(ac) || Double.isInfinite(bd) ||
+                Double.isInfinite(ad) || Double.isInfinite(bc))) {
+                // The result overflowed to infinity.
+                // Recover infinities from overflow by changing NaNs to 0 ...
+                a = changeNaNtoZero(a);
+                b = changeNaNtoZero(b);
+                c = changeNaNtoZero(c);
+                d = changeNaNtoZero(d);
+                recalc = true;
+            }
+            if (recalc) {
+                x = Double.POSITIVE_INFINITY * (a * c - b * d);
+                y = Double.POSITIVE_INFINITY * (a * d + b * c);
+            }
+        }
+        return action.apply(x, y);
+    }
+
+    /**
+     * Box values for the real or imaginary component of an infinite complex number.
+     * Any infinite value will be returned as one. Non-infinite values will be returned as zero.
+     * The sign is maintained.
+     *
+     * <pre>
+     *  inf  =  1
+     * -inf  = -1
+     *  x    =  0
+     * -x    = -0
+     * </pre>
+     *
+     * @param component the component
+     * @return The boxed value
+     */
+    private static double boxInfinity(double component) {
+        return Math.copySign(Double.isInfinite(component) ? 1.0 : 0.0, component);
+    }
+
+    /**
+     * Checks if the complex number is not zero.
+     *
+     * @param real the real component
+     * @param imaginary the imaginary component
+     * @return true if the complex is not zero
+     */
+    private static boolean isNotZero(double real, double imaginary) {
+        // The use of equals is deliberate.
+        // This method must distinguish NaN from zero thus ruling out:
+        // (real != 0.0 || imaginary != 0.0)
+        return !(real == 0.0 && imaginary == 0.0);
+    }
+
+    /**
+     * Change NaN to zero preserving the sign; otherwise return the value.
+     *
+     * @param value the value
+     * @return The new value
+     */
+    private static double changeNaNtoZero(double value) {
+        return Double.isNaN(value) ? Math.copySign(0.0, value) : value;
+    }
+
+    /**
+     * Returns a {@code Complex} whose value is:

Review Comment:
   Wrong javadoc. Copy the from Complex which uses the MathJax formula.
   
   However the note about divide by zero is useful so I would leave that in.



##########
commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CReferenceTest.java:
##########
@@ -162,7 +162,7 @@ static void assertEquals(Supplier<String> msg, double expected, double actual, l
      * @param operation1 Operation on the Complex object.
      * @param operation2 Operation on the complex real and imaginary parts.
      * @param expected Expected result.
-     * @param maxUlps Maximum units of least precision between the two values.
+     * @param maxUlps Maximum units of the least precision between the two values.

Review Comment:
   Wikipedia does not agree here: [ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place)
   
   Can you change all javadoc back to `units of least precision`



##########
commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexFunctions.java:
##########
@@ -677,6 +929,48 @@ private static <R> R log(DoubleUnaryOperator log,
         return action.apply(re, arg(real, imaginary));
     }
 
+    /**
+     * Returns the complex power of the first complex number raised to the power of
+     * second complex number.
+     * Implements the formula:
+     *
+     * <p>\[ z^x = e^{x \ln(z)} \]
+     *
+     * <p>If the complex number is zero then this method returns zero if the second complex number is positive
+     * in the real component and zero in the imaginary component;
+     * otherwise it returns NaN + iNaN.
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the power of the complex number.

Review Comment:
   Consumer for the power result.



##########
commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexFunctions.java:
##########
@@ -396,6 +399,255 @@ public static <R> R proj(double real, double imaginary, ComplexSink<R> action) {
         return action.apply(real, imaginary);
     }
 
+    /**
+     * Returns a {@code Object} whose value is {@code (real1 + real2, imaginary1 + imaginary2)}.
+     * Implements the formula:
+     *
+     * <p>\[ (a + i b) + (c + i d) = (a + c) + i (b + d) \]
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final added complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     * @see <a href="http://mathworld.wolfram.com/ComplexAddition.html">Complex Addition</a>
+     */
+    public static <R> R add(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        return action.apply(re1 + re2,
+            im1 + im2);
+    }
+
+    /**
+     * Returns a {@code Object} whose value is {@code (real1 - real2, imaginary1 - imaginary2)}.
+     * Implements the formula:
+     *
+     * <p>\[ (a + i b) - (c + i d) = (a - c) + i (b - d) \]
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final subtracted complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     * @see <a href="http://mathworld.wolfram.com/ComplexSubtraction.html">Complex Subtraction</a>
+     */
+    public static <R> R subtract(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        return action.apply(re1 - re2,
+            im1 - im2);
+    }
+
+    /**
+     * Returns a {@code Object} whose value is:
+     * <pre>
+     *  (a + i b)(c + i d) = (ac - bd) + i (ad + bc)</pre>
+     *
+     * <p>Recalculates to recover infinities as specified in C99 standard G.5.1.
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final multiplied complex number.
+     * @param <R> the return type of the supplied action.
+     * @return the object returned by the supplied action.
+     */
+    public static <R> R multiply(double re1, double im1, double re2, double im2, ComplexSink<R> action) {
+        double a = re1;
+        double b = im1;
+        double c = re2;
+        double d = im2;
+        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;
+
+        // --------------
+        // NaN can occur if:
+        // - any of (a,b,c,d) are NaN (for NaN or Infinite complex numbers)
+        // - a multiplication of infinity by zero (ac,bd,ad,bc).
+        // - a subtraction of infinity from infinity (e.g. ac - bd)
+        //   Note that (ac,bd,ad,bc) can be infinite due to overflow.
+        //
+        // Detect a NaN result and perform correction.
+        //
+        // Modification from the listing in ISO C99 G.5.1 (6)
+        // Do not correct infinity multiplied by zero. This is left as NaN.
+        // --------------
+
+        if (Double.isNaN(x) && Double.isNaN(y)) {
+            // Recover infinities that computed as NaN+iNaN ...
+            boolean recalc = false;
+            if ((Double.isInfinite(a) || Double.isInfinite(b)) &&
+                isNotZero(c, d)) {
+                // This complex is infinite.
+                // "Box" the infinity and change NaNs in the other factor to 0.
+                a = boxInfinity(a);
+                b = boxInfinity(b);
+                c = changeNaNtoZero(c);
+                d = changeNaNtoZero(d);
+                recalc = true;
+            }
+            if ((Double.isInfinite(c) || Double.isInfinite(d)) &&
+                isNotZero(a, b)) {
+                // The other complex is infinite.
+                // "Box" the infinity and change NaNs in the other factor to 0.
+                c = boxInfinity(c);
+                d = boxInfinity(d);
+                a = changeNaNtoZero(a);
+                b = changeNaNtoZero(b);
+                recalc = true;
+            }
+            if (!recalc && (Double.isInfinite(ac) || Double.isInfinite(bd) ||
+                Double.isInfinite(ad) || Double.isInfinite(bc))) {
+                // The result overflowed to infinity.
+                // Recover infinities from overflow by changing NaNs to 0 ...
+                a = changeNaNtoZero(a);
+                b = changeNaNtoZero(b);
+                c = changeNaNtoZero(c);
+                d = changeNaNtoZero(d);
+                recalc = true;
+            }
+            if (recalc) {
+                x = Double.POSITIVE_INFINITY * (a * c - b * d);
+                y = Double.POSITIVE_INFINITY * (a * d + b * c);
+            }
+        }
+        return action.apply(x, y);
+    }
+
+    /**
+     * Box values for the real or imaginary component of an infinite complex number.
+     * Any infinite value will be returned as one. Non-infinite values will be returned as zero.
+     * The sign is maintained.
+     *
+     * <pre>
+     *  inf  =  1
+     * -inf  = -1
+     *  x    =  0
+     * -x    = -0
+     * </pre>
+     *
+     * @param component the component
+     * @return The boxed value
+     */
+    private static double boxInfinity(double component) {
+        return Math.copySign(Double.isInfinite(component) ? 1.0 : 0.0, component);
+    }
+
+    /**
+     * Checks if the complex number is not zero.
+     *
+     * @param real the real component
+     * @param imaginary the imaginary component
+     * @return true if the complex is not zero
+     */
+    private static boolean isNotZero(double real, double imaginary) {
+        // The use of equals is deliberate.
+        // This method must distinguish NaN from zero thus ruling out:
+        // (real != 0.0 || imaginary != 0.0)
+        return !(real == 0.0 && imaginary == 0.0);
+    }
+
+    /**
+     * Change NaN to zero preserving the sign; otherwise return the value.
+     *
+     * @param value the value
+     * @return The new value
+     */
+    private static double changeNaNtoZero(double value) {
+        return Double.isNaN(value) ? Math.copySign(0.0, value) : value;
+    }
+
+    /**
+     * Returns a {@code Complex} whose value is:
+     * <pre>
+     * <code>
+     *   a + i b     (ac + bd) + i (bc - ad)
+     *   -------  =  -----------------------
+     *   c + i d            c<sup>2</sup> + d<sup>2</sup>
+     * </code>
+     * </pre>
+     *
+     * <p>Recalculates to recover infinities as specified in C99
+     * standard G.5.1. Method is fully in accordance with
+     * C++11 standards for complex numbers.</p>
+     *
+     * <p>Note: In the event of divide by zero this method produces the same result
+     * as dividing by a real-only zero using (add divide reference)
+     *
+     * @param re1 Real part \( a \) of the first complex number \( (a +ib) \).
+     * @param im1 Imaginary part \( b \) of the first complex number \( (a +ib) \).
+     * @param re2 Real part \( a \) of the second complex number \( (a +ib) \).
+     * @param im2 Imaginary part \( b \) of the second complex number \( (a +ib) \).
+     * @param action Consumer for the final divided complex number.

Review Comment:
   Consumer for the division result.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@commons.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org