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/06 18:29:00 UTC
[commons-numbers] 06/19: Optimise identity asin() to avoid Complex
object creation.
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 92cb49b1d77167ca62d26764096165e3890f30b2
Author: aherbert <ah...@apache.org>
AuthorDate: Fri Dec 6 13:32:59 2019 +0000
Optimise identity asin() to avoid Complex object creation.
Extract multiply to static method for use in asinh.
---
.../apache/commons/numbers/complex/Complex.java | 86 +++++++++++++++++-----
1 file changed, 68 insertions(+), 18 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 e239471..dcd3117 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
@@ -322,7 +322,20 @@ public final class Complex implements Serializable {
}
/**
- * Returns the
+ * Returns a {@code Complex} whose value is {@code this + (a + b i))}.
+ *
+ * <p>This function is used internally in trigonomic functions.
+ *
+ * @param a Real component a.
+ * @param b Imaginary component b.
+ * @return {@code this + (a + b i)}.
+ */
+ private Complex add(double a, double b) {
+ return new Complex(real + a, imaginary + b);
+ }
+
+ /**
+ * Returns the
* <a href="http://mathworld.wolfram.com/ComplexConjugate.html">conjugate</a>
* z̅ of this complex number z.
* <pre>
@@ -717,10 +730,26 @@ public final class Complex implements Serializable {
* @see <a href="http://mathworld.wolfram.com/ComplexMultiplication.html">Complex Muliplication</a>
*/
public Complex multiply(Complex factor) {
- double a = real;
- double b = imaginary;
- double c = factor.getReal();
- double d = factor.getImaginary();
+ return multiply(real, imaginary, factor.real, factor.imaginary);
+ }
+
+ /**
+ * Returns a {@code Complex} whose value is:
+ * <pre>
+ * (a + b i)(c + d i) = (ac - bd) + i (ad + bc)
+ * </pre>
+ *
+ * <p>Recalculates to recover infinities as specified in C.99
+ * standard G.5.1. Method is fully in accordance with
+ * C++11 standards for complex numbers.</p>
+ *
+ * @param a Real component of first number.
+ * @param b Imaginary component of first number.
+ * @param c Real component of second number.
+ * @param d Imaginary component of second number.
+ * @return (a + b i)(c + d i).
+ */
+ private static Complex multiply(double a, double b, double c, double d) {
final double ac = a * c;
final double bd = b * d;
final double ad = a * d;
@@ -744,7 +773,8 @@ public final class Complex implements Serializable {
if (Double.isNaN(x) && Double.isNaN(y)) {
// Recover infinities that computed as NaN+iNaN ...
boolean recalc = false;
- if (isInfinite() && isNotZero(c, d)) {
+ 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);
@@ -1002,7 +1032,8 @@ public final class Complex implements Serializable {
public Complex asin() {
// Define in terms of asinh
// asin(z) = -i asinh(iz)
- return multiplyByI().asinh().multiplyByNegI();
+ // Multiply this number by I, compute asinh, then multiply by back
+ return asinh(-imaginary, real, Complex::multiplyNegativeI);
}
/**
@@ -1068,43 +1099,62 @@ public final class Complex implements Serializable {
* @return the inverse hyperbolic sine of this complex number
*/
public Complex asinh() {
+ return asinh(real, imaginary, Complex::ofCartesian);
+ }
+
+ /**
+ * Compute the inverse hyperbolic sine of the complex number.
+ *
+ * <p>This function exists to allow implementation of the identity
+ * {@code sin(z) = -i sinh(iz)}.<p>
+ *
+ * @param real Real part.
+ * @param imaginary Imaginary part.
+ * @param constructor Constructor.
+ * @return the inverse hyperbolic sine of this complex number
+ */
+ private static Complex asinh(double real, double imaginary, ComplexConstructor constructor) {
if (Double.isFinite(real)) {
if (Double.isFinite(imaginary)) {
// Special case for zero
if (real == 0 && imaginary == 0) {
- return this;
+ return constructor.create(real, imaginary);
}
// ISO C99: Preserve the equality
// asinh(conj(z)) = conj(asinh(z))
// and the odd function: f(z) = -f(-z)
// by always computing on a positive valued Complex number.
- final UnaryOperator<Complex> g = mapToPositiveDomain();
- final Complex z = g.apply(this);
- final Complex result = z.square().add(1).sqrt().add(z).log();
- return g.apply(result);
+ final double a = Math.abs(real);
+ final double b = Math.abs(imaginary);
+ // square() is implemented using multiply
+ final Complex result = multiply(a, b, a, b).add(1).sqrt().add(a, b).log();
+ // Map back to the correct domain
+ return constructor.create(Math.copySign(result.real, real),
+ Math.copySign(result.imaginary, imaginary));
}
if (Double.isInfinite(imaginary)) {
- return new Complex(Math.copySign(Double.POSITIVE_INFINITY, real), Math.copySign(PI_OVER_2, imaginary));
+ return constructor.create(Math.copySign(Double.POSITIVE_INFINITY, real),
+ Math.copySign(PI_OVER_2, imaginary));
}
// imaginary is NaN
return NAN;
}
if (Double.isInfinite(real)) {
if (Double.isFinite(imaginary)) {
- return new Complex(real, Math.copySign(0, imaginary));
+ return constructor.create(real, Math.copySign(0, imaginary));
}
if (Double.isInfinite(imaginary)) {
- return new Complex(real, Math.copySign(PI_OVER_4, imaginary));
+ return constructor.create(real, Math.copySign(PI_OVER_4, imaginary));
}
// imaginary is NaN
- return new Complex(real, Double.NaN);
+ return constructor.create(real, Double.NaN);
}
// real is NaN
if (imaginary == 0) {
- return new Complex(Double.NaN, Math.copySign(0, imaginary));
+ return constructor.create(Double.NaN, Math.copySign(0, imaginary));
}
if (Double.isInfinite(imaginary)) {
- return new Complex(Double.POSITIVE_INFINITY, Double.NaN);
+ return constructor.create(Double.POSITIVE_INFINITY, Double.NaN);
}
// optionally raises the ‘‘invalid’’ floating-point exception, for finite y.
return NAN;