FieldComplex.java

  1. /*
  2.  * Licensed to the Hipparchus project under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The Hipparchus project licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.hipparchus.complex;

  18. import java.util.ArrayList;
  19. import java.util.List;

  20. import org.hipparchus.CalculusFieldElement;
  21. import org.hipparchus.Field;
  22. import org.hipparchus.exception.LocalizedCoreFormats;
  23. import org.hipparchus.exception.MathIllegalArgumentException;
  24. import org.hipparchus.exception.NullArgumentException;
  25. import org.hipparchus.util.FastMath;
  26. import org.hipparchus.util.FieldSinCos;
  27. import org.hipparchus.util.FieldSinhCosh;
  28. import org.hipparchus.util.MathArrays;
  29. import org.hipparchus.util.MathUtils;
  30. import org.hipparchus.util.Precision;

  31. /**
  32.  * Representation of a Complex number, i.e. a number which has both a
  33.  * real and imaginary part.
  34.  * <p>
  35.  * Implementations of arithmetic operations handle {@code NaN} and
  36.  * infinite values according to the rules for {@link java.lang.Double}, i.e.
  37.  * {@link #equals} is an equivalence relation for all instances that have
  38.  * a {@code NaN} in either real or imaginary part, e.g. the following are
  39.  * considered equal:
  40.  * <ul>
  41.  *  <li>{@code 1 + NaNi}</li>
  42.  *  <li>{@code NaN + i}</li>
  43.  *  <li>{@code NaN + NaNi}</li>
  44.  * </ul>
  45.  * <p>
  46.  * Note that this contradicts the IEEE-754 standard for floating
  47.  * point numbers (according to which the test {@code x == x} must fail if
  48.  * {@code x} is {@code NaN}). The method
  49.  * {@link org.hipparchus.util.Precision#equals(double,double,int)
  50.  * equals for primitive double} in {@link org.hipparchus.util.Precision}
  51.  * conforms with IEEE-754 while this class conforms with the standard behavior
  52.  * for Java object types.
  53.  * @param <T> the type of the field elements
  54.  * @since 2.0
  55.  */
  56. public class FieldComplex<T extends CalculusFieldElement<T>> implements CalculusFieldElement<FieldComplex<T>>  {

  57.     /** A real number representing log(10). */
  58.     private static final double LOG10 = 2.302585092994045684;

  59.     /** The imaginary part. */
  60.     private final T imaginary;

  61.     /** The real part. */
  62.     private final T real;

  63.     /** Record whether this complex number is equal to NaN. */
  64.     private final transient boolean isNaN;

  65.     /** Record whether this complex number is infinite. */
  66.     private final transient boolean isInfinite;

  67.     /**
  68.      * Create a complex number given only the real part.
  69.      *
  70.      * @param real Real part.
  71.      */
  72.     public FieldComplex(T real) {
  73.         this(real, real.getField().getZero());
  74.     }

  75.     /**
  76.      * Create a complex number given the real and imaginary parts.
  77.      *
  78.      * @param real Real part.
  79.      * @param imaginary Imaginary part.
  80.      */
  81.     public FieldComplex(T real, T imaginary) {
  82.         this.real = real;
  83.         this.imaginary = imaginary;

  84.         isNaN = real.isNaN() || imaginary.isNaN();
  85.         isInfinite = !isNaN &&
  86.             (real.isInfinite() || imaginary.isInfinite());
  87.     }

  88.     /** Get the square root of -1.
  89.      * @param field field the complex components belong to
  90.      * @return number representing "0.0 + 1.0i"
  91.      * @param <T> the type of the field elements
  92.      */
  93.     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getI(final Field<T> field) {
  94.         return new FieldComplex<>(field.getZero(), field.getOne());
  95.     }

  96.     /** Get the square root of -1.
  97.      * @param field field the complex components belong to
  98.      * @return number representing "0.0 _ 1.0i"
  99.      * @param <T> the type of the field elements
  100.      */
  101.     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getMinusI(final Field<T> field) {
  102.         return new FieldComplex<>(field.getZero(), field.getOne().negate());
  103.     }

  104.     /** Get a complex number representing "NaN + NaNi".
  105.      * @param field field the complex components belong to
  106.      * @return complex number representing "NaN + NaNi"
  107.      * @param <T> the type of the field elements
  108.      */
  109.     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getNaN(final Field<T> field) {
  110.         return new FieldComplex<>(field.getZero().add(Double.NaN), field.getZero().add(Double.NaN));
  111.     }

  112.     /** Get a complex number representing "+INF + INFi".
  113.      * @param field field the complex components belong to
  114.      * @return complex number representing "+INF + INFi"
  115.      * @param <T> the type of the field elements
  116.      */
  117.     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getInf(final Field<T> field) {
  118.         return new FieldComplex<>(field.getZero().add(Double.POSITIVE_INFINITY), field.getZero().add(Double.POSITIVE_INFINITY));
  119.     }

  120.     /** Get a complex number representing "1.0 + 0.0i".
  121.      * @param field field the complex components belong to
  122.      * @return complex number representing "1.0 + 0.0i"
  123.      * @param <T> the type of the field elements
  124.      */
  125.     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getOne(final Field<T> field) {
  126.         return new FieldComplex<>(field.getOne(), field.getZero());
  127.     }

  128.     /** Get a complex number representing "-1.0 + 0.0i".
  129.      * @param field field the complex components belong to
  130.      * @return complex number representing "-1.0 + 0.0i"
  131.      * @param <T> the type of the field elements
  132.      */
  133.     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getMinusOne(final Field<T> field) {
  134.         return new FieldComplex<>(field.getOne().negate(), field.getZero());
  135.     }

  136.     /** Get a complex number representing "0.0 + 0.0i".
  137.      * @param field field the complex components belong to
  138.      * @return complex number representing "0.0 + 0.0i
  139.      * @param <T> the type of the field elements
  140.      */
  141.     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getZero(final Field<T> field) {
  142.         return new FieldComplex<>(field.getZero(), field.getZero());
  143.     }

  144.     /** Get a complex number representing "π + 0.0i".
  145.      * @param field field the complex components belong to
  146.      * @return complex number representing "π + 0.0i
  147.      * @param <T> the type of the field elements
  148.      */
  149.     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getPi(final Field<T> field) {
  150.         return new FieldComplex<>(field.getZero().getPi(), field.getZero());
  151.     }

  152.     /**
  153.      * Return the absolute value of this complex number.
  154.      * Returns {@code NaN} if either real or imaginary part is {@code NaN}
  155.      * and {@code Double.POSITIVE_INFINITY} if neither part is {@code NaN},
  156.      * but at least one part is infinite.
  157.      *
  158.      * @return the absolute value.
  159.      */
  160.     @Override
  161.     public FieldComplex<T> abs() {
  162.         // we check NaN here because FastMath.hypot checks it after infinity
  163.         return isNaN ? getNaN(getPartsField()) : createComplex(FastMath.hypot(real, imaginary), getPartsField().getZero());
  164.     }

  165.     /**
  166.      * Returns a {@code Complex} whose value is
  167.      * {@code (this + addend)}.
  168.      * Uses the definitional formula
  169.      * <p>
  170.      *   {@code (a + bi) + (c + di) = (a+c) + (b+d)i}
  171.      * </p>
  172.      * If either {@code this} or {@code addend} has a {@code NaN} value in
  173.      * either part, {@link #getNaN(Field)} is returned; otherwise {@code Infinite}
  174.      * and {@code NaN} values are returned in the parts of the result
  175.      * according to the rules for {@link java.lang.Double} arithmetic.
  176.      *
  177.      * @param  addend Value to be added to this {@code Complex}.
  178.      * @return {@code this + addend}.
  179.      * @throws NullArgumentException if {@code addend} is {@code null}.
  180.      */
  181.     @Override
  182.     public FieldComplex<T> add(FieldComplex<T> addend) throws NullArgumentException {
  183.         MathUtils.checkNotNull(addend);
  184.         if (isNaN || addend.isNaN) {
  185.             return getNaN(getPartsField());
  186.         }

  187.         return createComplex(real.add(addend.getRealPart()),
  188.                              imaginary.add(addend.getImaginaryPart()));
  189.     }

  190.     /**
  191.      * Returns a {@code Complex} whose value is {@code (this + addend)},
  192.      * with {@code addend} interpreted as a real number.
  193.      *
  194.      * @param addend Value to be added to this {@code Complex}.
  195.      * @return {@code this + addend}.
  196.      * @see #add(FieldComplex)
  197.      */
  198.     public FieldComplex<T> add(T addend) {
  199.         if (isNaN || addend.isNaN()) {
  200.             return getNaN(getPartsField());
  201.         }

  202.         return createComplex(real.add(addend), imaginary);
  203.     }

  204.     /**
  205.      * Returns a {@code Complex} whose value is {@code (this + addend)},
  206.      * with {@code addend} interpreted as a real number.
  207.      *
  208.      * @param addend Value to be added to this {@code Complex}.
  209.      * @return {@code this + addend}.
  210.      * @see #add(FieldComplex)
  211.      */
  212.     @Override
  213.     public FieldComplex<T> add(double addend) {
  214.         if (isNaN || Double.isNaN(addend)) {
  215.             return getNaN(getPartsField());
  216.         }

  217.         return createComplex(real.add(addend), imaginary);
  218.     }

  219.     /**
  220.      * Returns the conjugate of this complex number.
  221.      * The conjugate of {@code a + bi} is {@code a - bi}.
  222.      * <p>
  223.      * {@link #getNaN(Field)} is returned if either the real or imaginary
  224.      * part of this Complex number equals {@code Double.NaN}.
  225.      * </p><p>
  226.      * If the imaginary part is infinite, and the real part is not
  227.      * {@code NaN}, the returned value has infinite imaginary part
  228.      * of the opposite sign, e.g. the conjugate of
  229.      * {@code 1 + POSITIVE_INFINITY i} is {@code 1 - NEGATIVE_INFINITY i}.
  230.      * </p>
  231.      * @return the conjugate of this Complex object.
  232.      */
  233.     public FieldComplex<T> conjugate() {
  234.         if (isNaN) {
  235.             return getNaN(getPartsField());
  236.         }

  237.         return createComplex(real, imaginary.negate());
  238.     }

  239.     /**
  240.      * Returns a {@code Complex} whose value is
  241.      * {@code (this / divisor)}.
  242.      * Implements the definitional formula
  243.      * <pre>
  244.      *  <code>
  245.      *    a + bi          ac + bd + (bc - ad)i
  246.      *    ----------- = -------------------------
  247.      *    c + di         c<sup>2</sup> + d<sup>2</sup>
  248.      *  </code>
  249.      * </pre>
  250.      * but uses
  251.      * <a href="http://doi.acm.org/10.1145/1039813.1039814">
  252.      * prescaling of operands</a> to limit the effects of overflows and
  253.      * underflows in the computation.
  254.      * <p>
  255.      * {@code Infinite} and {@code NaN} values are handled according to the
  256.      * following rules, applied in the order presented:
  257.      * <ul>
  258.      *  <li>If either {@code this} or {@code divisor} has a {@code NaN} value
  259.      *   in either part, {@link #getNaN(Field)} is returned.
  260.      *  </li>
  261.      *  <li>If {@code divisor} equals {@link #getZero(Field)}, {@link #getNaN(Field)} is returned.
  262.      *  </li>
  263.      *  <li>If {@code this} and {@code divisor} are both infinite,
  264.      *   {@link #getNaN(Field)} is returned.
  265.      *  </li>
  266.      *  <li>If {@code this} is finite (i.e., has no {@code Infinite} or
  267.      *   {@code NaN} parts) and {@code divisor} is infinite (one or both parts
  268.      *   infinite), {@link #getZero(Field)} is returned.
  269.      *  </li>
  270.      *  <li>If {@code this} is infinite and {@code divisor} is finite,
  271.      *   {@code NaN} values are returned in the parts of the result if the
  272.      *   {@link java.lang.Double} rules applied to the definitional formula
  273.      *   force {@code NaN} results.
  274.      *  </li>
  275.      * </ul>
  276.      *
  277.      * @param divisor Value by which this {@code Complex} is to be divided.
  278.      * @return {@code this / divisor}.
  279.      * @throws NullArgumentException if {@code divisor} is {@code null}.
  280.      */
  281.     @Override
  282.     public FieldComplex<T> divide(FieldComplex<T> divisor)
  283.         throws NullArgumentException {
  284.         MathUtils.checkNotNull(divisor);
  285.         if (isNaN || divisor.isNaN) {
  286.             return getNaN(getPartsField());
  287.         }

  288.         final T c = divisor.getRealPart();
  289.         final T d = divisor.getImaginaryPart();
  290.         if (c.isZero() && d.isZero()) {
  291.             return getNaN(getPartsField());
  292.         }

  293.         if (divisor.isInfinite() && !isInfinite()) {
  294.             return getZero(getPartsField());
  295.         }

  296.         if (FastMath.abs(c).getReal() < FastMath.abs(d).getReal()) {
  297.             T q = c.divide(d);
  298.             T invDen = c.multiply(q).add(d).reciprocal();
  299.             return createComplex(real.multiply(q).add(imaginary).multiply(invDen),
  300.                                  imaginary.multiply(q).subtract(real).multiply(invDen));
  301.         } else {
  302.             T q = d.divide(c);
  303.             T invDen = d.multiply(q).add(c).reciprocal();
  304.             return createComplex(imaginary.multiply(q).add(real).multiply(invDen),
  305.                                  imaginary.subtract(real.multiply(q)).multiply(invDen));
  306.         }
  307.     }

  308.     /**
  309.      * Returns a {@code Complex} whose value is {@code (this / divisor)},
  310.      * with {@code divisor} interpreted as a real number.
  311.      *
  312.      * @param  divisor Value by which this {@code Complex} is to be divided.
  313.      * @return {@code this / divisor}.
  314.      * @see #divide(FieldComplex)
  315.      */
  316.     public FieldComplex<T> divide(T divisor) {
  317.         if (isNaN || divisor.isNaN()) {
  318.             return getNaN(getPartsField());
  319.         }
  320.         if (divisor.isZero()) {
  321.             return getNaN(getPartsField());
  322.         }
  323.         if (divisor.isInfinite()) {
  324.             return !isInfinite() ? getZero(getPartsField()) : getNaN(getPartsField());
  325.         }
  326.         return createComplex(real.divide(divisor), imaginary.divide(divisor));
  327.     }

  328.     /**
  329.      * Returns a {@code Complex} whose value is {@code (this / divisor)},
  330.      * with {@code divisor} interpreted as a real number.
  331.      *
  332.      * @param  divisor Value by which this {@code Complex} is to be divided.
  333.      * @return {@code this / divisor}.
  334.      * @see #divide(FieldComplex)
  335.      */
  336.     @Override
  337.     public FieldComplex<T> divide(double divisor) {
  338.         if (isNaN || Double.isNaN(divisor)) {
  339.             return getNaN(getPartsField());
  340.         }
  341.         if (divisor == 0.0) {
  342.             return getNaN(getPartsField());
  343.         }
  344.         if (Double.isInfinite(divisor)) {
  345.             return !isInfinite() ? getZero(getPartsField()) : getNaN(getPartsField());
  346.         }
  347.         return createComplex(real.divide(divisor), imaginary.divide(divisor));
  348.     }

  349.     /** {@inheritDoc} */
  350.     @Override
  351.     public FieldComplex<T> reciprocal() {
  352.         if (isNaN) {
  353.             return getNaN(getPartsField());
  354.         }

  355.         if (real.isZero() && imaginary.isZero()) {
  356.             return getInf(getPartsField());
  357.         }

  358.         if (isInfinite) {
  359.             return getZero(getPartsField());
  360.         }

  361.         if (FastMath.abs(real).getReal() < FastMath.abs(imaginary).getReal()) {
  362.             T q = real.divide(imaginary);
  363.             T scale = real.multiply(q).add(imaginary).reciprocal();
  364.             return createComplex(scale.multiply(q), scale.negate());
  365.         } else {
  366.             T q = imaginary.divide(real);
  367.             T scale = imaginary.multiply(q).add(real).reciprocal();
  368.             return createComplex(scale, scale.negate().multiply(q));
  369.         }
  370.     }

  371.     /**
  372.      * Test for equality with another object.
  373.      * If both the real and imaginary parts of two complex numbers
  374.      * are exactly the same, and neither is {@code Double.NaN}, the two
  375.      * Complex objects are considered to be equal.
  376.      * The behavior is the same as for JDK's {@link Double#equals(Object)
  377.      * Double}:
  378.      * <ul>
  379.      *  <li>All {@code NaN} values are considered to be equal,
  380.      *   i.e, if either (or both) real and imaginary parts of the complex
  381.      *   number are equal to {@code Double.NaN}, the complex number is equal
  382.      *   to {@code NaN}.
  383.      *  </li>
  384.      *  <li>
  385.      *   Instances constructed with different representations of zero (i.e.
  386.      *   either "0" or "-0") are <em>not</em> considered to be equal.
  387.      *  </li>
  388.      * </ul>
  389.      *
  390.      * @param other Object to test for equality with this instance.
  391.      * @return {@code true} if the objects are equal, {@code false} if object
  392.      * is {@code null}, not an instance of {@code Complex}, or not equal to
  393.      * this instance.
  394.      */
  395.     @Override
  396.     public boolean equals(Object other) {
  397.         if (this == other) {
  398.             return true;
  399.         }
  400.         if (other instanceof FieldComplex){
  401.             @SuppressWarnings("unchecked")
  402.             FieldComplex<T> c = (FieldComplex<T>) other;
  403.             if (c.isNaN) {
  404.                 return isNaN;
  405.             } else {
  406.                 return real.equals(c.real) && imaginary.equals(c.imaginary);
  407.             }
  408.         }
  409.         return false;
  410.     }

  411.     /**
  412.      * Test for the floating-point equality between Complex objects.
  413.      * It returns {@code true} if both arguments are equal or within the
  414.      * range of allowed error (inclusive).
  415.      *
  416.      * @param x First value (cannot be {@code null}).
  417.      * @param y Second value (cannot be {@code null}).
  418.      * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
  419.      * values between the real (resp. imaginary) parts of {@code x} and
  420.      * {@code y}.
  421.      * @param <T> the type of the field elements
  422.      * @return {@code true} if there are fewer than {@code maxUlps} floating
  423.      * point values between the real (resp. imaginary) parts of {@code x}
  424.      * and {@code y}.
  425.      *
  426.      * @see Precision#equals(double,double,int)
  427.      */
  428.     public static <T extends CalculusFieldElement<T>>boolean equals(FieldComplex<T> x, FieldComplex<T> y, int maxUlps) {
  429.         return Precision.equals(x.real.getReal(), y.real.getReal(), maxUlps) &&
  430.                Precision.equals(x.imaginary.getReal(), y.imaginary.getReal(), maxUlps);
  431.     }

  432.     /**
  433.      * Returns {@code true} iff the values are equal as defined by
  434.      * {@link #equals(FieldComplex,FieldComplex,int) equals(x, y, 1)}.
  435.      *
  436.      * @param x First value (cannot be {@code null}).
  437.      * @param y Second value (cannot be {@code null}).
  438.      * @param <T> the type of the field elements
  439.      * @return {@code true} if the values are equal.
  440.      */
  441.     public static <T extends CalculusFieldElement<T>>boolean equals(FieldComplex<T> x, FieldComplex<T> y) {
  442.         return equals(x, y, 1);
  443.     }

  444.     /**
  445.      * Returns {@code true} if, both for the real part and for the imaginary
  446.      * part, there is no T value strictly between the arguments or the
  447.      * difference between them is within the range of allowed error
  448.      * (inclusive).  Returns {@code false} if either of the arguments is NaN.
  449.      *
  450.      * @param x First value (cannot be {@code null}).
  451.      * @param y Second value (cannot be {@code null}).
  452.      * @param eps Amount of allowed absolute error.
  453.      * @param <T> the type of the field elements
  454.      * @return {@code true} if the values are two adjacent floating point
  455.      * numbers or they are within range of each other.
  456.      *
  457.      * @see Precision#equals(double,double,double)
  458.      */
  459.     public static <T extends CalculusFieldElement<T>>boolean equals(FieldComplex<T> x, FieldComplex<T> y,
  460.                                                                     double eps) {
  461.         return Precision.equals(x.real.getReal(), y.real.getReal(), eps) &&
  462.                Precision.equals(x.imaginary.getReal(), y.imaginary.getReal(), eps);
  463.     }

  464.     /**
  465.      * Returns {@code true} if, both for the real part and for the imaginary
  466.      * part, there is no T value strictly between the arguments or the
  467.      * relative difference between them is smaller or equal to the given
  468.      * tolerance. Returns {@code false} if either of the arguments is NaN.
  469.      *
  470.      * @param x First value (cannot be {@code null}).
  471.      * @param y Second value (cannot be {@code null}).
  472.      * @param eps Amount of allowed relative error.
  473.      * @param <T> the type of the field elements
  474.      * @return {@code true} if the values are two adjacent floating point
  475.      * numbers or they are within range of each other.
  476.      *
  477.      * @see Precision#equalsWithRelativeTolerance(double,double,double)
  478.      */
  479.     public static <T extends CalculusFieldElement<T>>boolean equalsWithRelativeTolerance(FieldComplex<T> x,
  480.                                                                                          FieldComplex<T> y,
  481.                                                                                          double eps) {
  482.         return Precision.equalsWithRelativeTolerance(x.real.getReal(), y.real.getReal(), eps) &&
  483.                Precision.equalsWithRelativeTolerance(x.imaginary.getReal(), y.imaginary.getReal(), eps);
  484.     }

  485.     /**
  486.      * Get a hashCode for the complex number.
  487.      * Any {@code Double.NaN} value in real or imaginary part produces
  488.      * the same hash code {@code 7}.
  489.      *
  490.      * @return a hash code value for this object.
  491.      */
  492.     @Override
  493.     public int hashCode() {
  494.         if (isNaN) {
  495.             return 7;
  496.         }
  497.         return 37 * (17 * imaginary.hashCode() + real.hashCode());
  498.     }

  499.     /** {@inheritDoc}
  500.      * <p>
  501.      * This implementation considers +0.0 and -0.0 to be equal for both
  502.      * real and imaginary components.
  503.      * </p>
  504.      */
  505.     @Override
  506.     public boolean isZero() {
  507.         return real.isZero() && imaginary.isZero();
  508.     }

  509.     /**
  510.      * Access the imaginary part.
  511.      *
  512.      * @return the imaginary part.
  513.      */
  514.     public T getImaginary() {
  515.         return imaginary;
  516.     }

  517.     /**
  518.      * Access the imaginary part.
  519.      *
  520.      * @return the imaginary part.
  521.      */
  522.     public T getImaginaryPart() {
  523.         return imaginary;
  524.     }

  525.     /**
  526.      * Access the real part.
  527.      *
  528.      * @return the real part.
  529.      */
  530.     @Override
  531.     public double getReal() {
  532.         return real.getReal();
  533.     }

  534.     /** {@inheritDoc} */
  535.     @Override
  536.     public FieldComplex<T> getAddendum() {
  537.         return new FieldComplex<>(real.getAddendum(), imaginary);
  538.     }

  539.     /**
  540.      * Access the real part.
  541.      *
  542.      * @return the real part.
  543.      */
  544.     public T getRealPart() {
  545.         return real;
  546.     }

  547.     /**
  548.      * Checks whether either or both parts of this complex number is
  549.      * {@code NaN}.
  550.      *
  551.      * @return true if either or both parts of this complex number is
  552.      * {@code NaN}; false otherwise.
  553.      */
  554.     @Override
  555.     public boolean isNaN() {
  556.         return isNaN;
  557.     }

  558.     /** Check whether the instance is real (i.e. imaginary part is zero).
  559.      * @return true if imaginary part is zero
  560.       */
  561.     public boolean isReal() {
  562.         return imaginary.isZero();
  563.     }

  564.     /** Check whether the instance is an integer (i.e. imaginary part is zero and real part has no fractional part).
  565.      * @return true if imaginary part is zero and real part has no fractional part
  566.      */
  567.     public boolean isMathematicalInteger() {
  568.         return isReal() && Precision.isMathematicalInteger(real.getReal());
  569.     }

  570.     /**
  571.      * Checks whether either the real or imaginary part of this complex number
  572.      * takes an infinite value (either {@code Double.POSITIVE_INFINITY} or
  573.      * {@code Double.NEGATIVE_INFINITY}) and neither part
  574.      * is {@code NaN}.
  575.      *
  576.      * @return true if one or both parts of this complex number are infinite
  577.      * and neither part is {@code NaN}.
  578.      */
  579.     @Override
  580.     public boolean isInfinite() {
  581.         return isInfinite;
  582.     }

  583.     /**
  584.      * Returns a {@code Complex} whose value is {@code this * factor}.
  585.      * Implements preliminary checks for {@code NaN} and infinity followed by
  586.      * the definitional formula:
  587.      * <p>
  588.      *   {@code (a + bi)(c + di) = (ac - bd) + (ad + bc)i}
  589.      * </p>
  590.      * Returns {@link #getNaN(Field)} if either {@code this} or {@code factor} has one or
  591.      * more {@code NaN} parts.
  592.      * <p>
  593.      * Returns {@link #getInf(Field)} if neither {@code this} nor {@code factor} has one
  594.      * or more {@code NaN} parts and if either {@code this} or {@code factor}
  595.      * has one or more infinite parts (same result is returned regardless of
  596.      * the sign of the components).
  597.      * </p><p>
  598.      * Returns finite values in components of the result per the definitional
  599.      * formula in all remaining cases.</p>
  600.      *
  601.      * @param  factor value to be multiplied by this {@code Complex}.
  602.      * @return {@code this * factor}.
  603.      * @throws NullArgumentException if {@code factor} is {@code null}.
  604.      */
  605.     @Override
  606.     public FieldComplex<T> multiply(FieldComplex<T> factor)
  607.         throws NullArgumentException {
  608.         MathUtils.checkNotNull(factor);
  609.         if (isNaN || factor.isNaN) {
  610.             return getNaN(getPartsField());
  611.         }
  612.         if (real.isInfinite() ||
  613.             imaginary.isInfinite() ||
  614.             factor.real.isInfinite() ||
  615.             factor.imaginary.isInfinite()) {
  616.             // we don't use isInfinite() to avoid testing for NaN again
  617.             return getInf(getPartsField());
  618.         }
  619.         return createComplex(real.linearCombination(real, factor.real, imaginary.negate(), factor.imaginary),
  620.                              real.linearCombination(real, factor.imaginary, imaginary, factor.real));
  621.     }

  622.     /**
  623.      * Returns a {@code Complex} whose value is {@code this * factor}, with {@code factor}
  624.      * interpreted as a integer number.
  625.      *
  626.      * @param  factor value to be multiplied by this {@code Complex}.
  627.      * @return {@code this * factor}.
  628.      * @see #multiply(FieldComplex)
  629.      */
  630.     @Override
  631.     public FieldComplex<T> multiply(final int factor) {
  632.         if (isNaN) {
  633.             return getNaN(getPartsField());
  634.         }
  635.         if (real.isInfinite() || imaginary.isInfinite()) {
  636.             return getInf(getPartsField());
  637.         }
  638.         return createComplex(real.multiply(factor), imaginary.multiply(factor));
  639.     }

  640.     /**
  641.      * Returns a {@code Complex} whose value is {@code this * factor}, with {@code factor}
  642.      * interpreted as a real number.
  643.      *
  644.      * @param  factor value to be multiplied by this {@code Complex}.
  645.      * @return {@code this * factor}.
  646.      * @see #multiply(FieldComplex)
  647.      */
  648.     @Override
  649.     public FieldComplex<T> multiply(double factor) {
  650.         if (isNaN || Double.isNaN(factor)) {
  651.             return getNaN(getPartsField());
  652.         }
  653.         if (real.isInfinite() ||
  654.             imaginary.isInfinite() ||
  655.             Double.isInfinite(factor)) {
  656.             // we don't use isInfinite() to avoid testing for NaN again
  657.             return getInf(getPartsField());
  658.         }
  659.         return createComplex(real.multiply(factor), imaginary.multiply(factor));
  660.     }

  661.     /**
  662.      * Returns a {@code Complex} whose value is {@code this * factor}, with {@code factor}
  663.      * interpreted as a real number.
  664.      *
  665.      * @param  factor value to be multiplied by this {@code Complex}.
  666.      * @return {@code this * factor}.
  667.      * @see #multiply(FieldComplex)
  668.      */
  669.     public FieldComplex<T> multiply(T factor) {
  670.         if (isNaN || factor.isNaN()) {
  671.             return getNaN(getPartsField());
  672.         }
  673.         if (real.isInfinite() ||
  674.             imaginary.isInfinite() ||
  675.             factor.isInfinite()) {
  676.             // we don't use isInfinite() to avoid testing for NaN again
  677.             return getInf(getPartsField());
  678.         }
  679.         return createComplex(real.multiply(factor), imaginary.multiply(factor));
  680.     }

  681.     /** Compute this * i.
  682.      * @return this * i
  683.      * @since 2.0
  684.      */
  685.     public FieldComplex<T> multiplyPlusI() {
  686.         return createComplex(imaginary.negate(), real);
  687.     }

  688.     /** Compute this *- -i.
  689.      * @return this * i
  690.      * @since 2.0
  691.      */
  692.     public FieldComplex<T> multiplyMinusI() {
  693.         return createComplex(imaginary, real.negate());
  694.     }

  695.     @Override
  696.     public FieldComplex<T> square() {
  697.         return multiply(this);
  698.     }

  699.     /**
  700.      * Returns a {@code Complex} whose value is {@code (-this)}.
  701.      * Returns {@code NaN} if either real or imaginary
  702.      * part of this Complex number is {@code Double.NaN}.
  703.      *
  704.      * @return {@code -this}.
  705.      */
  706.     @Override
  707.     public FieldComplex<T> negate() {
  708.         if (isNaN) {
  709.             return getNaN(getPartsField());
  710.         }

  711.         return createComplex(real.negate(), imaginary.negate());
  712.     }

  713.     /**
  714.      * Returns a {@code Complex} whose value is
  715.      * {@code (this - subtrahend)}.
  716.      * Uses the definitional formula
  717.      * <p>
  718.      *  {@code (a + bi) - (c + di) = (a-c) + (b-d)i}
  719.      * </p>
  720.      * If either {@code this} or {@code subtrahend} has a {@code NaN]} value in either part,
  721.      * {@link #getNaN(Field)} is returned; otherwise infinite and {@code NaN} values are
  722.      * returned in the parts of the result according to the rules for
  723.      * {@link java.lang.Double} arithmetic.
  724.      *
  725.      * @param  subtrahend value to be subtracted from this {@code Complex}.
  726.      * @return {@code this - subtrahend}.
  727.      * @throws NullArgumentException if {@code subtrahend} is {@code null}.
  728.      */
  729.     @Override
  730.     public FieldComplex<T> subtract(FieldComplex<T> subtrahend)
  731.         throws NullArgumentException {
  732.         MathUtils.checkNotNull(subtrahend);
  733.         if (isNaN || subtrahend.isNaN) {
  734.             return getNaN(getPartsField());
  735.         }

  736.         return createComplex(real.subtract(subtrahend.getRealPart()),
  737.                              imaginary.subtract(subtrahend.getImaginaryPart()));
  738.     }

  739.     /**
  740.      * Returns a {@code Complex} whose value is
  741.      * {@code (this - subtrahend)}.
  742.      *
  743.      * @param  subtrahend value to be subtracted from this {@code Complex}.
  744.      * @return {@code this - subtrahend}.
  745.      * @see #subtract(FieldComplex)
  746.      */
  747.     @Override
  748.     public FieldComplex<T> subtract(double subtrahend) {
  749.         if (isNaN || Double.isNaN(subtrahend)) {
  750.             return getNaN(getPartsField());
  751.         }
  752.         return createComplex(real.subtract(subtrahend), imaginary);
  753.     }

  754.     /**
  755.      * Returns a {@code Complex} whose value is
  756.      * {@code (this - subtrahend)}.
  757.      *
  758.      * @param  subtrahend value to be subtracted from this {@code Complex}.
  759.      * @return {@code this - subtrahend}.
  760.      * @see #subtract(FieldComplex)
  761.      */
  762.     public FieldComplex<T> subtract(T subtrahend) {
  763.         if (isNaN || subtrahend.isNaN()) {
  764.             return getNaN(getPartsField());
  765.         }
  766.         return createComplex(real.subtract(subtrahend), imaginary);
  767.     }

  768.     /**
  769.      * Compute the
  770.      * <a href="http://mathworld.wolfram.com/InverseCosine.html" TARGET="_top">
  771.      * inverse cosine</a> of this complex number.
  772.      * Implements the formula:
  773.      * <p>
  774.      *  {@code acos(z) = -i (log(z + i (sqrt(1 - z<sup>2</sup>))))}
  775.      * </p>
  776.      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
  777.      * input argument is {@code NaN} or infinite.
  778.      *
  779.      * @return the inverse cosine of this complex number.
  780.      */
  781.     @Override
  782.     public FieldComplex<T> acos() {
  783.         if (isNaN) {
  784.             return getNaN(getPartsField());
  785.         }

  786.         return this.add(this.sqrt1z().multiplyPlusI()).log().multiplyMinusI();
  787.     }

  788.     /**
  789.      * Compute the
  790.      * <a href="http://mathworld.wolfram.com/InverseSine.html" TARGET="_top">
  791.      * inverse sine</a> of this complex number.
  792.      * Implements the formula:
  793.      * <p>
  794.      *  {@code asin(z) = -i (log(sqrt(1 - z<sup>2</sup>) + iz))}
  795.      * </p><p>
  796.      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
  797.      * input argument is {@code NaN} or infinite.</p>
  798.      *
  799.      * @return the inverse sine of this complex number.
  800.      */
  801.     @Override
  802.     public FieldComplex<T> asin() {
  803.         if (isNaN) {
  804.             return getNaN(getPartsField());
  805.         }

  806.         return sqrt1z().add(this.multiplyPlusI()).log().multiplyMinusI();
  807.     }

  808.     /**
  809.      * Compute the
  810.      * <a href="http://mathworld.wolfram.com/InverseTangent.html" TARGET="_top">
  811.      * inverse tangent</a> of this complex number.
  812.      * Implements the formula:
  813.      * <p>
  814.      * {@code atan(z) = (i/2) log((1 - iz)/(1 + iz))}
  815.      * </p><p>
  816.      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
  817.      * input argument is {@code NaN} or infinite.</p>
  818.      *
  819.      * @return the inverse tangent of this complex number
  820.      */
  821.     @Override
  822.     public FieldComplex<T> atan() {
  823.         if (isNaN) {
  824.             return getNaN(getPartsField());
  825.         }

  826.         final T one = getPartsField().getOne();
  827.         if (real.isZero()) {

  828.             // singularity at ±i
  829.             if (imaginary.multiply(imaginary).subtract(one).isZero()) {
  830.                 return getNaN(getPartsField());
  831.             }

  832.             // branch cut on imaginary axis
  833.             final T zero = getPartsField().getZero();
  834.             final FieldComplex<T> tmp = createComplex(one.add(imaginary).divide(one.subtract(imaginary)), zero).
  835.                                         log().multiplyPlusI().multiply(0.5);
  836.             return createComplex(FastMath.copySign(tmp.real, real), tmp.imaginary);

  837.         } else if (imaginary.isZero()) {
  838.             // taking care to preserve the sign of the zero imaginary part
  839.             return createComplex(FastMath.atan(real), imaginary);
  840.         } else {
  841.             // regular formula
  842.             final FieldComplex<T> n = createComplex(one.add(imaginary), real.negate());
  843.             final FieldComplex<T> d = createComplex(one.subtract(imaginary),  real);
  844.             return n.divide(d).log().multiplyPlusI().multiply(0.5);
  845.         }

  846.     }

  847.     /**
  848.      * Compute the
  849.      * <a href="http://mathworld.wolfram.com/Cosine.html" TARGET="_top">
  850.      * cosine</a> of this complex number.
  851.      * Implements the formula:
  852.      * <p>
  853.      *  {@code cos(a + bi) = cos(a)cosh(b) - sin(a)sinh(b)i}
  854.      * </p><p>
  855.      * where the (real) functions on the right-hand side are
  856.      * {@link FastMath#sin}, {@link FastMath#cos},
  857.      * {@link FastMath#cosh} and {@link FastMath#sinh}.
  858.      * </p><p>
  859.      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
  860.      * input argument is {@code NaN}.
  861.      * </p><p>
  862.      * Infinite values in real or imaginary parts of the input may result in
  863.      * infinite or NaN values returned in parts of the result.</p>
  864.      * <pre>
  865.      *  Examples:
  866.      *  <code>
  867.      *   cos(1 &plusmn; INFINITY i) = 1 ∓ INFINITY i
  868.      *   cos(&plusmn;INFINITY + i) = NaN + NaN i
  869.      *   cos(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
  870.      *  </code>
  871.      * </pre>
  872.      *
  873.      * @return the cosine of this complex number.
  874.      */
  875.     @Override
  876.     public FieldComplex<T> cos() {
  877.         if (isNaN) {
  878.             return getNaN(getPartsField());
  879.         }

  880.         final FieldSinCos<T>   scr  = FastMath.sinCos(real);
  881.         final FieldSinhCosh<T> schi = FastMath.sinhCosh(imaginary);
  882.         return createComplex(scr.cos().multiply(schi.cosh()), scr.sin().negate().multiply(schi.sinh()));
  883.     }

  884.     /**
  885.      * Compute the
  886.      * <a href="http://mathworld.wolfram.com/HyperbolicCosine.html" TARGET="_top">
  887.      * hyperbolic cosine</a> of this complex number.
  888.      * Implements the formula:
  889.      * <pre>
  890.      *  <code>
  891.      *   cosh(a + bi) = cosh(a)cos(b) + sinh(a)sin(b)i
  892.      *  </code>
  893.      * </pre>
  894.      * where the (real) functions on the right-hand side are
  895.      * {@link FastMath#sin}, {@link FastMath#cos},
  896.      * {@link FastMath#cosh} and {@link FastMath#sinh}.
  897.      * <p>
  898.      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
  899.      * input argument is {@code NaN}.
  900.      * </p>
  901.      * Infinite values in real or imaginary parts of the input may result in
  902.      * infinite or NaN values returned in parts of the result.
  903.      * <pre>
  904.      *  Examples:
  905.      *  <code>
  906.      *   cosh(1 &plusmn; INFINITY i) = NaN + NaN i
  907.      *   cosh(&plusmn;INFINITY + i) = INFINITY &plusmn; INFINITY i
  908.      *   cosh(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
  909.      *  </code>
  910.      * </pre>
  911.      *
  912.      * @return the hyperbolic cosine of this complex number.
  913.      */
  914.     @Override
  915.     public FieldComplex<T> cosh() {
  916.         if (isNaN) {
  917.             return getNaN(getPartsField());
  918.         }

  919.         final FieldSinhCosh<T> schr = FastMath.sinhCosh(real);
  920.         final FieldSinCos<T>   sci  = FastMath.sinCos(imaginary);
  921.         return createComplex(schr.cosh().multiply(sci.cos()), schr.sinh().multiply(sci.sin()));
  922.     }

  923.     /**
  924.      * Compute the
  925.      * <a href="http://mathworld.wolfram.com/ExponentialFunction.html" TARGET="_top">
  926.      * exponential function</a> of this complex number.
  927.      * Implements the formula:
  928.      * <pre>
  929.      *  <code>
  930.      *   exp(a + bi) = exp(a)cos(b) + exp(a)sin(b)i
  931.      *  </code>
  932.      * </pre>
  933.      * where the (real) functions on the right-hand side are
  934.      * {@link FastMath#exp(CalculusFieldElement)} p}, {@link FastMath#cos(CalculusFieldElement)}, and
  935.      * {@link FastMath#sin(CalculusFieldElement)}.
  936.      * <p>
  937.      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
  938.      * input argument is {@code NaN}.
  939.      * </p>
  940.      * Infinite values in real or imaginary parts of the input may result in
  941.      * infinite or NaN values returned in parts of the result.
  942.      * <pre>
  943.      *  Examples:
  944.      *  <code>
  945.      *   exp(1 &plusmn; INFINITY i) = NaN + NaN i
  946.      *   exp(INFINITY + i) = INFINITY + INFINITY i
  947.      *   exp(-INFINITY + i) = 0 + 0i
  948.      *   exp(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
  949.      *  </code>
  950.      * </pre>
  951.      *
  952.      * @return <code><i>e</i><sup>this</sup></code>.
  953.      */
  954.     @Override
  955.     public FieldComplex<T> exp() {
  956.         if (isNaN) {
  957.             return getNaN(getPartsField());
  958.         }

  959.         final T              expReal = FastMath.exp(real);
  960.         final FieldSinCos<T> sc      = FastMath.sinCos(imaginary);
  961.         return createComplex(expReal.multiply(sc.cos()), expReal.multiply(sc.sin()));
  962.     }

  963.     /** {@inheritDoc} */
  964.     @Override
  965.     public FieldComplex<T> expm1() {
  966.         if (isNaN) {
  967.             return getNaN(getPartsField());
  968.         }

  969.         final T              expm1Real = FastMath.expm1(real);
  970.         final FieldSinCos<T> sc        = FastMath.sinCos(imaginary);
  971.         return createComplex(expm1Real.multiply(sc.cos()), expm1Real.multiply(sc.sin()));
  972.     }

  973.     /**
  974.      * Compute the
  975.      * <a href="http://mathworld.wolfram.com/NaturalLogarithm.html" TARGET="_top">
  976.      * natural logarithm</a> of this complex number.
  977.      * Implements the formula:
  978.      * <pre>
  979.      *  <code>
  980.      *   log(a + bi) = ln(|a + bi|) + arg(a + bi)i
  981.      *  </code>
  982.      * </pre>
  983.      * where ln on the right hand side is {@link FastMath#log(CalculusFieldElement)},
  984.      * {@code |a + bi|} is the modulus, {@link #abs},  and
  985.      * {@code arg(a + bi) = }{@link FastMath#atan2}(b, a).
  986.      * <p>
  987.      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
  988.      * input argument is {@code NaN}.
  989.      * </p>
  990.      * Infinite (or critical) values in real or imaginary parts of the input may
  991.      * result in infinite or NaN values returned in parts of the result.
  992.      * <pre>
  993.      *  Examples:
  994.      *  <code>
  995.      *   log(1 &plusmn; INFINITY i) = INFINITY &plusmn; (&pi;/2)i
  996.      *   log(INFINITY + i) = INFINITY + 0i
  997.      *   log(-INFINITY + i) = INFINITY + &pi;i
  998.      *   log(INFINITY &plusmn; INFINITY i) = INFINITY &plusmn; (&pi;/4)i
  999.      *   log(-INFINITY &plusmn; INFINITY i) = INFINITY &plusmn; (3&pi;/4)i
  1000.      *   log(0 + 0i) = -INFINITY + 0i
  1001.      *  </code>
  1002.      * </pre>
  1003.      *
  1004.      * @return the value <code>ln &nbsp; this</code>, the natural logarithm
  1005.      * of {@code this}.
  1006.      */
  1007.     @Override
  1008.     public FieldComplex<T> log() {
  1009.         if (isNaN) {
  1010.             return getNaN(getPartsField());
  1011.         }

  1012.         return createComplex(FastMath.log(FastMath.hypot(real, imaginary)),
  1013.                              FastMath.atan2(imaginary, real));
  1014.     }

  1015.     /** {@inheritDoc} */
  1016.     @Override
  1017.     public FieldComplex<T> log1p() {
  1018.         return add(1.0).log();
  1019.     }

  1020.     /** {@inheritDoc} */
  1021.     @Override
  1022.     public FieldComplex<T> log10() {
  1023.         return log().divide(LOG10);
  1024.     }

  1025.     /**
  1026.      * Returns of value of this complex number raised to the power of {@code x}.
  1027.      * <p>
  1028.      * If {@code x} is a real number whose real part has an integer value, returns {@link #pow(int)},
  1029.      * if both {@code this} and {@code x} are real and {@link FastMath#pow(double, double)}
  1030.      * with the corresponding real arguments would return a finite number (neither NaN
  1031.      * nor infinite), then returns the same value converted to {@code Complex},
  1032.      * with the same special cases.
  1033.      * In all other cases real cases, implements y<sup>x</sup> = exp(x&middot;log(y)).
  1034.      * </p>
  1035.      *
  1036.      * @param  x exponent to which this {@code Complex} is to be raised.
  1037.      * @return <code> this<sup>x</sup></code>.
  1038.      * @throws NullArgumentException if x is {@code null}.
  1039.      */
  1040.     @Override
  1041.     public FieldComplex<T> pow(FieldComplex<T> x)
  1042.         throws NullArgumentException {

  1043.         MathUtils.checkNotNull(x);

  1044.         if (x.imaginary.isZero()) {
  1045.             final int nx = (int) FastMath.rint(x.real.getReal());
  1046.             if (x.real.getReal() == nx) {
  1047.                 // integer power
  1048.                 return pow(nx);
  1049.             } else if (this.imaginary.isZero()) {
  1050.                 // check real implementation that handles a bunch of special cases
  1051.                 final T realPow = FastMath.pow(this.real, x.real);
  1052.                 if (realPow.isFinite()) {
  1053.                     return createComplex(realPow, getPartsField().getZero());
  1054.                 }
  1055.             }
  1056.         }

  1057.         // generic implementation
  1058.         return this.log().multiply(x).exp();

  1059.     }


  1060.     /**
  1061.      * Returns of value of this complex number raised to the power of {@code x}.
  1062.      * <p>
  1063.      * If {@code x} has an integer value, returns {@link #pow(int)},
  1064.      * if {@code this} is real and {@link FastMath#pow(double, double)}
  1065.      * with the corresponding real arguments would return a finite number (neither NaN
  1066.      * nor infinite), then returns the same value converted to {@code Complex},
  1067.      * with the same special cases.
  1068.      * In all other cases real cases, implements y<sup>x</sup> = exp(x&middot;log(y)).
  1069.      * </p>
  1070.      *
  1071.      * @param  x exponent to which this {@code Complex} is to be raised.
  1072.      * @return <code> this<sup>x</sup></code>.
  1073.      */
  1074.     public FieldComplex<T> pow(T x) {

  1075.         final int nx = (int) FastMath.rint(x.getReal());
  1076.         if (x.getReal() == nx) {
  1077.             // integer power
  1078.             return pow(nx);
  1079.         } else if (this.imaginary.isZero()) {
  1080.             // check real implementation that handles a bunch of special cases
  1081.             final T realPow = FastMath.pow(this.real, x);
  1082.             if (realPow.isFinite()) {
  1083.                 return createComplex(realPow, getPartsField().getZero());
  1084.             }
  1085.         }

  1086.         // generic implementation
  1087.         return this.log().multiply(x).exp();

  1088.     }

  1089.     /**
  1090.      * Returns of value of this complex number raised to the power of {@code x}.
  1091.      * <p>
  1092.      * If {@code x} has an integer value, returns {@link #pow(int)},
  1093.      * if {@code this} is real and {@link FastMath#pow(double, double)}
  1094.      * with the corresponding real arguments would return a finite number (neither NaN
  1095.      * nor infinite), then returns the same value converted to {@code Complex},
  1096.      * with the same special cases.
  1097.      * In all other cases real cases, implements y<sup>x</sup> = exp(x&middot;log(y)).
  1098.      * </p>
  1099.      *
  1100.      * @param  x exponent to which this {@code Complex} is to be raised.
  1101.      * @return <code> this<sup>x</sup></code>.
  1102.      */
  1103.     @Override
  1104.     public FieldComplex<T> pow(double x) {

  1105.         final int nx = (int) FastMath.rint(x);
  1106.         if (x == nx) {
  1107.             // integer power
  1108.             return pow(nx);
  1109.         } else if (this.imaginary.isZero()) {
  1110.             // check real implementation that handles a bunch of special cases
  1111.             final T realPow = FastMath.pow(this.real, x);
  1112.             if (realPow.isFinite()) {
  1113.                 return createComplex(realPow, getPartsField().getZero());
  1114.             }
  1115.         }

  1116.         // generic implementation
  1117.         return this.log().multiply(x).exp();

  1118.     }

  1119.      /** {@inheritDoc} */
  1120.     @Override
  1121.     public FieldComplex<T> pow(final int n) {

  1122.         FieldComplex<T> result = getField().getOne();
  1123.         final boolean invert;
  1124.         int p = n;
  1125.         if (p < 0) {
  1126.             invert = true;
  1127.             p = -p;
  1128.         } else {
  1129.             invert = false;
  1130.         }

  1131.         // Exponentiate by successive squaring
  1132.         FieldComplex<T> square = this;
  1133.         while (p > 0) {
  1134.             if ((p & 0x1) > 0) {
  1135.                 result = result.multiply(square);
  1136.             }
  1137.             square = square.multiply(square);
  1138.             p = p >> 1;
  1139.         }

  1140.         return invert ? result.reciprocal() : result;

  1141.     }

  1142.      /**
  1143.       * Compute the
  1144.      * <a href="http://mathworld.wolfram.com/Sine.html" TARGET="_top">
  1145.      * sine</a>
  1146.      * of this complex number.
  1147.      * Implements the formula:
  1148.      * <pre>
  1149.      *  <code>
  1150.      *   sin(a + bi) = sin(a)cosh(b) + cos(a)sinh(b)i
  1151.      *  </code>
  1152.      * </pre>
  1153.      * where the (real) functions on the right-hand side are
  1154.      * {@link FastMath#sin}, {@link FastMath#cos},
  1155.      * {@link FastMath#cosh} and {@link FastMath#sinh}.
  1156.      * <p>
  1157.      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
  1158.      * input argument is {@code NaN}.
  1159.      * </p><p>
  1160.      * Infinite values in real or imaginary parts of the input may result in
  1161.      * infinite or {@code NaN} values returned in parts of the result.
  1162.      * <pre>
  1163.      *  Examples:
  1164.      *  <code>
  1165.      *   sin(1 &plusmn; INFINITY i) = 1 &plusmn; INFINITY i
  1166.      *   sin(&plusmn;INFINITY + i) = NaN + NaN i
  1167.      *   sin(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
  1168.      *  </code>
  1169.      * </pre>
  1170.      *
  1171.      * @return the sine of this complex number.
  1172.      */
  1173.     @Override
  1174.     public FieldComplex<T> sin() {
  1175.         if (isNaN) {
  1176.             return getNaN(getPartsField());
  1177.         }

  1178.         final FieldSinCos<T>   scr  = FastMath.sinCos(real);
  1179.         final FieldSinhCosh<T> schi = FastMath.sinhCosh(imaginary);
  1180.         return createComplex(scr.sin().multiply(schi.cosh()), scr.cos().multiply(schi.sinh()));

  1181.     }

  1182.     /** {@inheritDoc}
  1183.      */
  1184.     @Override
  1185.     public FieldSinCos<FieldComplex<T>> sinCos() {
  1186.         if (isNaN) {
  1187.             return new FieldSinCos<>(getNaN(getPartsField()), getNaN(getPartsField()));
  1188.         }

  1189.         final FieldSinCos<T>   scr = FastMath.sinCos(real);
  1190.         final FieldSinhCosh<T> schi = FastMath.sinhCosh(imaginary);
  1191.         return new FieldSinCos<>(createComplex(scr.sin().multiply(schi.cosh()), scr.cos().multiply(schi.sinh())),
  1192.                                  createComplex(scr.cos().multiply(schi.cosh()), scr.sin().negate().multiply(schi.sinh())));
  1193.     }

  1194.     /** {@inheritDoc} */
  1195.     @Override
  1196.     public FieldComplex<T> atan2(FieldComplex<T> x) {

  1197.         // compute r = sqrt(x^2+y^2)
  1198.         final FieldComplex<T> r = x.square().add(multiply(this)).sqrt();

  1199.         if (x.real.getReal() >= 0) {
  1200.             // compute atan2(y, x) = 2 atan(y / (r + x))
  1201.             return divide(r.add(x)).atan().multiply(2);
  1202.         } else {
  1203.             // compute atan2(y, x) = +/- pi - 2 atan(y / (r - x))
  1204.             return divide(r.subtract(x)).atan().multiply(-2).add(x.real.getPi());
  1205.         }
  1206.     }

  1207.     /** {@inheritDoc}
  1208.      * <p>
  1209.      * Branch cuts are on the real axis, below +1.
  1210.      * </p>
  1211.      */
  1212.     @Override
  1213.     public FieldComplex<T> acosh() {
  1214.         final FieldComplex<T> sqrtPlus  = add(1).sqrt();
  1215.         final FieldComplex<T> sqrtMinus = subtract(1).sqrt();
  1216.         return add(sqrtPlus.multiply(sqrtMinus)).log();
  1217.     }

  1218.     /** {@inheritDoc}
  1219.      * <p>
  1220.      * Branch cuts are on the imaginary axis, above +i and below -i.
  1221.      * </p>
  1222.      */
  1223.     @Override
  1224.     public FieldComplex<T> asinh() {
  1225.         return add(multiply(this).add(1.0).sqrt()).log();
  1226.     }

  1227.     /** {@inheritDoc}
  1228.      * <p>
  1229.      * Branch cuts are on the real axis, above +1 and below -1.
  1230.      * </p>
  1231.      */
  1232.     @Override
  1233.     public FieldComplex<T> atanh() {
  1234.         final FieldComplex<T> logPlus  = add(1).log();
  1235.         final FieldComplex<T> logMinus = createComplex(getPartsField().getOne().subtract(real), imaginary.negate()).log();
  1236.         return logPlus.subtract(logMinus).multiply(0.5);
  1237.     }

  1238.     /**
  1239.      * Compute the
  1240.      * <a href="http://mathworld.wolfram.com/HyperbolicSine.html" TARGET="_top">
  1241.      * hyperbolic sine</a> of this complex number.
  1242.      * Implements the formula:
  1243.      * <pre>
  1244.      *  <code>
  1245.      *   sinh(a + bi) = sinh(a)cos(b)) + cosh(a)sin(b)i
  1246.      *  </code>
  1247.      * </pre>
  1248.      * where the (real) functions on the right-hand side are
  1249.      * {@link FastMath#sin}, {@link FastMath#cos},
  1250.      * {@link FastMath#cosh} and {@link FastMath#sinh}.
  1251.      * <p>
  1252.      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
  1253.      * input argument is {@code NaN}.
  1254.      * </p><p>
  1255.      * Infinite values in real or imaginary parts of the input may result in
  1256.      * infinite or NaN values returned in parts of the result.
  1257.      * <pre>
  1258.      *  Examples:
  1259.      *  <code>
  1260.      *   sinh(1 &plusmn; INFINITY i) = NaN + NaN i
  1261.      *   sinh(&plusmn;INFINITY + i) = &plusmn; INFINITY + INFINITY i
  1262.      *   sinh(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
  1263.      *  </code>
  1264.      * </pre>
  1265.      *
  1266.      * @return the hyperbolic sine of {@code this}.
  1267.      */
  1268.     @Override
  1269.     public FieldComplex<T> sinh() {
  1270.         if (isNaN) {
  1271.             return getNaN(getPartsField());
  1272.         }

  1273.         final FieldSinhCosh<T> schr = FastMath.sinhCosh(real);
  1274.         final FieldSinCos<T>   sci  = FastMath.sinCos(imaginary);
  1275.         return createComplex(schr.sinh().multiply(sci.cos()), schr.cosh().multiply(sci.sin()));
  1276.     }

  1277.     /** {@inheritDoc}
  1278.      */
  1279.     @Override
  1280.     public FieldSinhCosh<FieldComplex<T>> sinhCosh() {
  1281.         if (isNaN) {
  1282.             return new FieldSinhCosh<>(getNaN(getPartsField()), getNaN(getPartsField()));
  1283.         }

  1284.         final FieldSinhCosh<T> schr = FastMath.sinhCosh(real);
  1285.         final FieldSinCos<T>   sci  = FastMath.sinCos(imaginary);
  1286.         return new FieldSinhCosh<>(createComplex(schr.sinh().multiply(sci.cos()), schr.cosh().multiply(sci.sin())),
  1287.                                    createComplex(schr.cosh().multiply(sci.cos()), schr.sinh().multiply(sci.sin())));
  1288.     }

  1289.     /**
  1290.      * Compute the
  1291.      * <a href="http://mathworld.wolfram.com/SquareRoot.html" TARGET="_top">
  1292.      * square root</a> of this complex number.
  1293.      * Implements the following algorithm to compute {@code sqrt(a + bi)}:
  1294.      * <ol><li>Let {@code t = sqrt((|a| + |a + bi|) / 2)}</li>
  1295.      * <li><pre>if {@code  a ≥ 0} return {@code t + (b/2t)i}
  1296.      *  else return {@code |b|/2t + sign(b)t i }</pre></li>
  1297.      * </ol>
  1298.      * where <ul>
  1299.      * <li>{@code |a| = }{@link FastMath#abs(CalculusFieldElement) abs(a)}</li>
  1300.      * <li>{@code |a + bi| = }{@link FastMath#hypot(CalculusFieldElement, CalculusFieldElement) hypot(a, b)}</li>
  1301.      * <li>{@code sign(b) = }{@link FastMath#copySign(CalculusFieldElement, CalculusFieldElement) copySign(1, b)}
  1302.      * </ul>
  1303.      * The real part is therefore always nonnegative.
  1304.      * <p>
  1305.      * Returns {@link #getNaN(Field) NaN} if either real or imaginary part of the
  1306.      * input argument is {@code NaN}.
  1307.      * </p>
  1308.      * <p>
  1309.      * Infinite values in real or imaginary parts of the input may result in
  1310.      * infinite or NaN values returned in parts of the result.
  1311.      * </p>
  1312.      * <pre>
  1313.      *  Examples:
  1314.      *  <code>
  1315.      *   sqrt(1 ± ∞ i) = ∞ + NaN i
  1316.      *   sqrt(∞ + i) = ∞ + 0i
  1317.      *   sqrt(-∞ + i) = 0 + ∞ i
  1318.      *   sqrt(∞ ± ∞ i) = ∞ + NaN i
  1319.      *   sqrt(-∞ ± ∞ i) = NaN ± ∞ i
  1320.      *  </code>
  1321.      * </pre>
  1322.      *
  1323.      * @return the square root of {@code this} with nonnegative real part.
  1324.      */
  1325.     @Override
  1326.     public FieldComplex<T> sqrt() {
  1327.         if (isNaN) {
  1328.             return getNaN(getPartsField());
  1329.         }

  1330.         if (isZero()) {
  1331.             return getZero(getPartsField());
  1332.         }

  1333.         T t = FastMath.sqrt((FastMath.abs(real).add(FastMath.hypot(real, imaginary))).multiply(0.5));
  1334.         if (real.getReal() >= 0.0) {
  1335.             return createComplex(t, imaginary.divide(t.multiply(2)));
  1336.         } else {
  1337.             return createComplex(FastMath.abs(imaginary).divide(t.multiply(2)),
  1338.                                  FastMath.copySign(t, imaginary));
  1339.         }
  1340.     }

  1341.     /**
  1342.      * Compute the
  1343.      * <a href="http://mathworld.wolfram.com/SquareRoot.html" TARGET="_top">
  1344.      * square root</a> of <code>1 - this<sup>2</sup></code> for this complex
  1345.      * number.
  1346.      * Computes the result directly as
  1347.      * {@code sqrt(ONE.subtract(z.square()))}.
  1348.      * <p>
  1349.      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
  1350.      * input argument is {@code NaN}.
  1351.      * </p>
  1352.      * Infinite values in real or imaginary parts of the input may result in
  1353.      * infinite or NaN values returned in parts of the result.
  1354.      *
  1355.      * @return the square root of <code>1 - this<sup>2</sup></code>.
  1356.      */
  1357.     public FieldComplex<T> sqrt1z() {
  1358.         final FieldComplex<T> t2 = this.square();
  1359.         return createComplex(getPartsField().getOne().subtract(t2.real), t2.imaginary.negate()).sqrt();
  1360.     }

  1361.     /** {@inheritDoc}
  1362.      * <p>
  1363.      * This implementation compute the principal cube root by using a branch cut along real negative axis.
  1364.      * </p>
  1365.      */
  1366.     @Override
  1367.     public FieldComplex<T> cbrt() {
  1368.         final T              magnitude = FastMath.cbrt(abs().getRealPart());
  1369.         final FieldSinCos<T> sc        = FastMath.sinCos(getArgument().divide(3));
  1370.         return createComplex(magnitude.multiply(sc.cos()), magnitude.multiply(sc.sin()));
  1371.     }

  1372.     /** {@inheritDoc}
  1373.      * <p>
  1374.      * This implementation compute the principal n<sup>th</sup> root by using a branch cut along real negative axis.
  1375.      * </p>
  1376.      */
  1377.     @Override
  1378.     public FieldComplex<T> rootN(int n) {
  1379.         final T              magnitude = FastMath.pow(abs().getRealPart(), 1.0 / n);
  1380.         final FieldSinCos<T> sc        = FastMath.sinCos(getArgument().divide(n));
  1381.         return createComplex(magnitude.multiply(sc.cos()), magnitude.multiply(sc.sin()));
  1382.     }

  1383.     /**
  1384.      * Compute the
  1385.      * <a href="http://mathworld.wolfram.com/Tangent.html" TARGET="_top">
  1386.      * tangent</a> of this complex number.
  1387.      * Implements the formula:
  1388.      * <pre>
  1389.      *  <code>
  1390.      *   tan(a + bi) = sin(2a)/(cos(2a)+cosh(2b)) + [sinh(2b)/(cos(2a)+cosh(2b))]i
  1391.      *  </code>
  1392.      * </pre>
  1393.      * where the (real) functions on the right-hand side are
  1394.      * {@link FastMath#sin}, {@link FastMath#cos}, {@link FastMath#cosh} and
  1395.      * {@link FastMath#sinh}.
  1396.      * <p>
  1397.      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
  1398.      * input argument is {@code NaN}.
  1399.      * </p>
  1400.      * Infinite (or critical) values in real or imaginary parts of the input may
  1401.      * result in infinite or NaN values returned in parts of the result.
  1402.      * <pre>
  1403.      *  Examples:
  1404.      *  <code>
  1405.      *   tan(a &plusmn; INFINITY i) = 0 &plusmn; i
  1406.      *   tan(&plusmn;INFINITY + bi) = NaN + NaN i
  1407.      *   tan(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
  1408.      *   tan(&plusmn;&pi;/2 + 0 i) = &plusmn;INFINITY + NaN i
  1409.      *  </code>
  1410.      * </pre>
  1411.      *
  1412.      * @return the tangent of {@code this}.
  1413.      */
  1414.     @Override
  1415.     public FieldComplex<T> tan() {
  1416.         if (isNaN || real.isInfinite()) {
  1417.             return getNaN(getPartsField());
  1418.         }
  1419.         if (imaginary.getReal() > 20.0) {
  1420.             return getI(getPartsField());
  1421.         }
  1422.         if (imaginary.getReal() < -20.0) {
  1423.             return getMinusI(getPartsField());
  1424.         }

  1425.         final FieldSinCos<T> sc2r = FastMath.sinCos(real.multiply(2));
  1426.         T imaginary2 = imaginary.multiply(2);
  1427.         T d = sc2r.cos().add(FastMath.cosh(imaginary2));

  1428.         return createComplex(sc2r.sin().divide(d), FastMath.sinh(imaginary2).divide(d));

  1429.     }

  1430.     /**
  1431.      * Compute the
  1432.      * <a href="http://mathworld.wolfram.com/HyperbolicTangent.html" TARGET="_top">
  1433.      * hyperbolic tangent</a> of this complex number.
  1434.      * Implements the formula:
  1435.      * <pre>
  1436.      *  <code>
  1437.      *   tan(a + bi) = sinh(2a)/(cosh(2a)+cos(2b)) + [sin(2b)/(cosh(2a)+cos(2b))]i
  1438.      *  </code>
  1439.      * </pre>
  1440.      * where the (real) functions on the right-hand side are
  1441.      * {@link FastMath#sin}, {@link FastMath#cos}, {@link FastMath#cosh} and
  1442.      * {@link FastMath#sinh}.
  1443.      * <p>
  1444.      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
  1445.      * input argument is {@code NaN}.
  1446.      * </p>
  1447.      * Infinite values in real or imaginary parts of the input may result in
  1448.      * infinite or NaN values returned in parts of the result.
  1449.      * <pre>
  1450.      *  Examples:
  1451.      *  <code>
  1452.      *   tanh(a &plusmn; INFINITY i) = NaN + NaN i
  1453.      *   tanh(&plusmn;INFINITY + bi) = &plusmn;1 + 0 i
  1454.      *   tanh(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
  1455.      *   tanh(0 + (&pi;/2)i) = NaN + INFINITY i
  1456.      *  </code>
  1457.      * </pre>
  1458.      *
  1459.      * @return the hyperbolic tangent of {@code this}.
  1460.      */
  1461.     @Override
  1462.     public FieldComplex<T> tanh() {
  1463.         if (isNaN || imaginary.isInfinite()) {
  1464.             return getNaN(getPartsField());
  1465.         }
  1466.         if (real.getReal() > 20.0) {
  1467.             return getOne(getPartsField());
  1468.         }
  1469.         if (real.getReal() < -20.0) {
  1470.             return getMinusOne(getPartsField());
  1471.         }
  1472.         T real2 = real.multiply(2);
  1473.         final FieldSinCos<T> sc2i = FastMath.sinCos(imaginary.multiply(2));
  1474.         T d = FastMath.cosh(real2).add(sc2i.cos());

  1475.         return createComplex(FastMath.sinh(real2).divide(d), sc2i.sin().divide(d));
  1476.     }



  1477.     /**
  1478.      * Compute the argument of this complex number.
  1479.      * The argument is the angle phi between the positive real axis and
  1480.      * the point representing this number in the complex plane.
  1481.      * The value returned is between -PI (not inclusive)
  1482.      * and PI (inclusive), with negative values returned for numbers with
  1483.      * negative imaginary parts.
  1484.      * <p>
  1485.      * If either real or imaginary part (or both) is NaN, NaN is returned.
  1486.      * Infinite parts are handled as {@code Math.atan2} handles them,
  1487.      * essentially treating finite parts as zero in the presence of an
  1488.      * infinite coordinate and returning a multiple of pi/4 depending on
  1489.      * the signs of the infinite parts.
  1490.      * See the javadoc for {@code Math.atan2} for full details.
  1491.      *
  1492.      * @return the argument of {@code this}.
  1493.      */
  1494.     public T getArgument() {
  1495.         return FastMath.atan2(getImaginaryPart(), getRealPart());
  1496.     }

  1497.     /**
  1498.      * Computes the n-th roots of this complex number.
  1499.      * The nth roots are defined by the formula:
  1500.      * <pre>
  1501.      *  <code>
  1502.      *   z<sub>k</sub> = abs<sup>1/n</sup> (cos(phi + 2&pi;k/n) + i (sin(phi + 2&pi;k/n))
  1503.      *  </code>
  1504.      * </pre>
  1505.      * for <i>{@code k=0, 1, ..., n-1}</i>, where {@code abs} and {@code phi}
  1506.      * are respectively the {@link #abs() modulus} and
  1507.      * {@link #getArgument() argument} of this complex number.
  1508.      * <p>
  1509.      * If one or both parts of this complex number is NaN, a list with just
  1510.      * one element, {@link #getNaN(Field)} is returned.
  1511.      * if neither part is NaN, but at least one part is infinite, the result
  1512.      * is a one-element list containing {@link #getInf(Field)}.
  1513.      *
  1514.      * @param n Degree of root.
  1515.      * @return a List of all {@code n}-th roots of {@code this}.
  1516.      * @throws MathIllegalArgumentException if {@code n <= 0}.
  1517.      */
  1518.     public List<FieldComplex<T>> nthRoot(int n) throws MathIllegalArgumentException {

  1519.         if (n <= 0) {
  1520.             throw new MathIllegalArgumentException(LocalizedCoreFormats.CANNOT_COMPUTE_NTH_ROOT_FOR_NEGATIVE_N,
  1521.                                                    n);
  1522.         }

  1523.         final List<FieldComplex<T>> result = new ArrayList<>();

  1524.         if (isNaN) {
  1525.             result.add(getNaN(getPartsField()));
  1526.             return result;
  1527.         }
  1528.         if (isInfinite()) {
  1529.             result.add(getInf(getPartsField()));
  1530.             return result;
  1531.         }

  1532.         // nth root of abs -- faster / more accurate to use a solver here?
  1533.         final T nthRootOfAbs = FastMath.pow(FastMath.hypot(real, imaginary), 1.0 / n);

  1534.         // Compute nth roots of complex number with k = 0, 1, ... n-1
  1535.         final T nthPhi = getArgument().divide(n);
  1536.         final double slice = 2 * FastMath.PI / n;
  1537.         T innerPart = nthPhi;
  1538.         for (int k = 0; k < n ; k++) {
  1539.             // inner part
  1540.             final FieldSinCos<T> scInner = FastMath.sinCos(innerPart);
  1541.             final T realPart = nthRootOfAbs.multiply(scInner.cos());
  1542.             final T imaginaryPart = nthRootOfAbs.multiply(scInner.sin());
  1543.             result.add(createComplex(realPart, imaginaryPart));
  1544.             innerPart = innerPart.add(slice);
  1545.         }

  1546.         return result;
  1547.     }

  1548.     /**
  1549.      * Create a complex number given the real and imaginary parts.
  1550.      *
  1551.      * @param realPart Real part.
  1552.      * @param imaginaryPart Imaginary part.
  1553.      * @return a new complex number instance.
  1554.      *
  1555.      * @see #valueOf(CalculusFieldElement, CalculusFieldElement)
  1556.      */
  1557.     protected FieldComplex<T> createComplex(final T realPart, final T imaginaryPart) {
  1558.         return new FieldComplex<>(realPart, imaginaryPart);
  1559.     }

  1560.     /**
  1561.      * Create a complex number given the real and imaginary parts.
  1562.      *
  1563.      * @param realPart Real part.
  1564.      * @param imaginaryPart Imaginary part.
  1565.      * @param <T> the type of the field elements
  1566.      * @return a Complex instance.
  1567.      */
  1568.     public static <T extends CalculusFieldElement<T>> FieldComplex<T>
  1569.         valueOf(T realPart, T imaginaryPart) {
  1570.         if (realPart.isNaN() || imaginaryPart.isNaN()) {
  1571.             return getNaN(realPart.getField());
  1572.         }
  1573.         return new FieldComplex<>(realPart, imaginaryPart);
  1574.     }

  1575.     /**
  1576.      * Create a complex number given only the real part.
  1577.      *
  1578.      * @param realPart Real part.
  1579.      * @param <T> the type of the field elements
  1580.      * @return a Complex instance.
  1581.      */
  1582.     public static <T extends CalculusFieldElement<T>> FieldComplex<T>
  1583.         valueOf(T realPart) {
  1584.         if (realPart.isNaN()) {
  1585.             return getNaN(realPart.getField());
  1586.         }
  1587.         return new FieldComplex<>(realPart);
  1588.     }

  1589.     /** {@inheritDoc} */
  1590.     @Override
  1591.     public FieldComplex<T> newInstance(double realPart) {
  1592.         return valueOf(getPartsField().getZero().newInstance(realPart));
  1593.     }

  1594.     /** {@inheritDoc} */
  1595.     @Override
  1596.     public FieldComplexField<T> getField() {
  1597.         return FieldComplexField.getField(getPartsField());
  1598.     }

  1599.     /** Get the {@link Field} the real and imaginary parts belong to.
  1600.      * @return {@link Field} the real and imaginary parts belong to
  1601.      */
  1602.     public Field<T> getPartsField() {
  1603.         return real.getField();
  1604.     }

  1605.     /** {@inheritDoc} */
  1606.     @Override
  1607.     public String toString() {
  1608.         return "(" + real + ", " + imaginary + ")";
  1609.     }

  1610.     /** {@inheritDoc} */
  1611.     @Override
  1612.     public FieldComplex<T> scalb(int n) {
  1613.         return createComplex(FastMath.scalb(real, n), FastMath.scalb(imaginary, n));
  1614.     }

  1615.     /** {@inheritDoc} */
  1616.     @Override
  1617.     public FieldComplex<T> ulp() {
  1618.         return createComplex(FastMath.ulp(real), FastMath.ulp(imaginary));
  1619.     }

  1620.     /** {@inheritDoc} */
  1621.     @Override
  1622.     public FieldComplex<T> hypot(FieldComplex<T> y) {
  1623.         if (isInfinite() || y.isInfinite()) {
  1624.             return getInf(getPartsField());
  1625.         } else if (isNaN() || y.isNaN()) {
  1626.             return getNaN(getPartsField());
  1627.         } else {
  1628.             return square().add(y.square()).sqrt();
  1629.         }
  1630.     }

  1631.     /** {@inheritDoc} */
  1632.     @Override
  1633.     public FieldComplex<T> linearCombination(final FieldComplex<T>[] a, final FieldComplex<T>[] b)
  1634.         throws MathIllegalArgumentException {
  1635.         final int n = 2 * a.length;
  1636.         final T[] realA      = MathArrays.buildArray(getPartsField(), n);
  1637.         final T[] realB      = MathArrays.buildArray(getPartsField(), n);
  1638.         final T[] imaginaryA = MathArrays.buildArray(getPartsField(), n);
  1639.         final T[] imaginaryB = MathArrays.buildArray(getPartsField(), n);
  1640.         for (int i = 0; i < a.length; ++i)  {
  1641.             final FieldComplex<T> ai = a[i];
  1642.             final FieldComplex<T> bi = b[i];
  1643.             realA[2 * i    ]      = ai.real;
  1644.             realA[2 * i + 1]      = ai.imaginary.negate();
  1645.             realB[2 * i    ]      = bi.real;
  1646.             realB[2 * i + 1]      = bi.imaginary;
  1647.             imaginaryA[2 * i    ] = ai.real;
  1648.             imaginaryA[2 * i + 1] = ai.imaginary;
  1649.             imaginaryB[2 * i    ] = bi.imaginary;
  1650.             imaginaryB[2 * i + 1] = bi.real;
  1651.         }
  1652.         return createComplex(real.linearCombination(realA,  realB),
  1653.                              real.linearCombination(imaginaryA, imaginaryB));
  1654.     }

  1655.     /** {@inheritDoc} */
  1656.     @Override
  1657.     public FieldComplex<T> linearCombination(final double[] a, final FieldComplex<T>[] b)
  1658.         throws MathIllegalArgumentException {
  1659.         final int n = a.length;
  1660.         final T[] realB      = MathArrays.buildArray(getPartsField(), n);
  1661.         final T[] imaginaryB = MathArrays.buildArray(getPartsField(), n);
  1662.         for (int i = 0; i < a.length; ++i)  {
  1663.             final FieldComplex<T> bi = b[i];
  1664.             realB[i]      = bi.real;
  1665.             imaginaryB[i] = bi.imaginary;
  1666.         }
  1667.         return createComplex(real.linearCombination(a,  realB),
  1668.                              real.linearCombination(a, imaginaryB));
  1669.     }

  1670.     /** {@inheritDoc} */
  1671.     @Override
  1672.     public FieldComplex<T> linearCombination(final FieldComplex<T> a1, final FieldComplex<T> b1, final FieldComplex<T> a2, final FieldComplex<T> b2) {
  1673.         return createComplex(real.linearCombination(a1.real, b1.real,
  1674.                                                     a1.imaginary.negate(), b1.imaginary,
  1675.                                                     a2.real, b2.real,
  1676.                                                     a2.imaginary.negate(), b2.imaginary),
  1677.                              real.linearCombination(a1.real, b1.imaginary,
  1678.                                                     a1.imaginary, b1.real,
  1679.                                                     a2.real, b2.imaginary,
  1680.                                                     a2.imaginary, b2.real));
  1681.     }

  1682.     /** {@inheritDoc} */
  1683.     @Override
  1684.     public FieldComplex<T> linearCombination(final double a1, final FieldComplex<T> b1, final double a2, final FieldComplex<T> b2) {
  1685.         return createComplex(real.linearCombination(a1, b1.real,
  1686.                                                     a2, b2.real),
  1687.                              real.linearCombination(a1, b1.imaginary,
  1688.                                                     a2, b2.imaginary));
  1689.     }

  1690.     /** {@inheritDoc} */
  1691.     @Override
  1692.     public FieldComplex<T> linearCombination(final FieldComplex<T> a1, final FieldComplex<T> b1,
  1693.                                                 final FieldComplex<T> a2, final FieldComplex<T> b2,
  1694.                                                 final FieldComplex<T> a3, final FieldComplex<T> b3) {
  1695.         FieldComplex<T>[] a = MathArrays.buildArray(getField(), 3);
  1696.         a[0] = a1;
  1697.         a[1] = a2;
  1698.         a[2] = a3;
  1699.         FieldComplex<T>[] b = MathArrays.buildArray(getField(), 3);
  1700.         b[0] = b1;
  1701.         b[1] = b2;
  1702.         b[2] = b3;
  1703.         return linearCombination(a, b);
  1704.     }

  1705.     /** {@inheritDoc} */
  1706.     @Override
  1707.     public FieldComplex<T> linearCombination(final double a1, final FieldComplex<T> b1,
  1708.                                                 final double a2, final FieldComplex<T> b2,
  1709.                                                 final double a3, final FieldComplex<T> b3) {
  1710.         FieldComplex<T>[] b = MathArrays.buildArray(getField(), 3);
  1711.         b[0] = b1;
  1712.         b[1] = b2;
  1713.         b[2] = b3;
  1714.         return linearCombination(new double[]  { a1, a2, a3 }, b);
  1715.     }

  1716.     /** {@inheritDoc} */
  1717.     @Override
  1718.     public FieldComplex<T> linearCombination(final FieldComplex<T> a1, final FieldComplex<T> b1,
  1719.                                                 final FieldComplex<T> a2, final FieldComplex<T> b2,
  1720.                                                 final FieldComplex<T> a3, final FieldComplex<T> b3,
  1721.                                                 final FieldComplex<T> a4, final FieldComplex<T> b4) {
  1722.         FieldComplex<T>[] a = MathArrays.buildArray(getField(), 4);
  1723.         a[0] = a1;
  1724.         a[1] = a2;
  1725.         a[2] = a3;
  1726.         a[3] = a4;
  1727.         FieldComplex<T>[] b = MathArrays.buildArray(getField(), 4);
  1728.         b[0] = b1;
  1729.         b[1] = b2;
  1730.         b[2] = b3;
  1731.         b[3] = b4;
  1732.         return linearCombination(a, b);
  1733.     }

  1734.     /** {@inheritDoc} */
  1735.     @Override
  1736.     public FieldComplex<T> linearCombination(final double a1, final FieldComplex<T> b1,
  1737.                                                 final double a2, final FieldComplex<T> b2,
  1738.                                                 final double a3, final FieldComplex<T> b3,
  1739.                                                 final double a4, final FieldComplex<T> b4) {
  1740.         FieldComplex<T>[] b = MathArrays.buildArray(getField(), 4);
  1741.         b[0] = b1;
  1742.         b[1] = b2;
  1743.         b[2] = b3;
  1744.         b[3] = b4;
  1745.         return linearCombination(new double[]  { a1, a2, a3, a4 }, b);
  1746.     }

  1747.     /** {@inheritDoc} */
  1748.     @Override
  1749.     public FieldComplex<T> ceil() {
  1750.         return createComplex(FastMath.ceil(getRealPart()), FastMath.ceil(getImaginaryPart()));
  1751.     }

  1752.     /** {@inheritDoc} */
  1753.     @Override
  1754.     public FieldComplex<T> floor() {
  1755.         return createComplex(FastMath.floor(getRealPart()), FastMath.floor(getImaginaryPart()));
  1756.     }

  1757.     /** {@inheritDoc} */
  1758.     @Override
  1759.     public FieldComplex<T> rint() {
  1760.         return createComplex(FastMath.rint(getRealPart()), FastMath.rint(getImaginaryPart()));
  1761.     }

  1762.     /** {@inheritDoc}
  1763.      * <p>
  1764.      * for complex numbers, the integer n corresponding to {@code this.subtract(remainder(a)).divide(a)}
  1765.      * is a <a href="https://en.wikipedia.org/wiki/Gaussian_integer">Wikipedia - Gaussian integer</a>.
  1766.      * </p>
  1767.      */
  1768.     @Override
  1769.     public FieldComplex<T> remainder(final double a) {
  1770.         return createComplex(FastMath.IEEEremainder(getRealPart(), a), FastMath.IEEEremainder(getImaginaryPart(), a));
  1771.     }

  1772.     /** {@inheritDoc}
  1773.      * <p>
  1774.      * for complex numbers, the integer n corresponding to {@code this.subtract(remainder(a)).divide(a)}
  1775.      * is a <a href="https://en.wikipedia.org/wiki/Gaussian_integer">Wikipedia - Gaussian integer</a>.
  1776.      * </p>
  1777.      */
  1778.     @Override
  1779.     public FieldComplex<T> remainder(final FieldComplex<T> a) {
  1780.         final FieldComplex<T> complexQuotient = divide(a);
  1781.         final T  qRInt           = FastMath.rint(complexQuotient.real);
  1782.         final T  qIInt           = FastMath.rint(complexQuotient.imaginary);
  1783.         return createComplex(real.subtract(qRInt.multiply(a.real)).add(qIInt.multiply(a.imaginary)),
  1784.                              imaginary.subtract(qRInt.multiply(a.imaginary)).subtract(qIInt.multiply(a.real)));
  1785.     }

  1786.     /** {@inheritDoc} */
  1787.     @Override
  1788.     public FieldComplex<T> sign() {
  1789.         if (isNaN() || isZero()) {
  1790.             return this;
  1791.         } else {
  1792.             return this.divide(FastMath.hypot(real, imaginary));
  1793.         }
  1794.     }

  1795.     /** {@inheritDoc}
  1796.      * <p>
  1797.      * The signs of real and imaginary parts are copied independently.
  1798.      * </p>
  1799.      */
  1800.     @Override
  1801.     public FieldComplex<T> copySign(final FieldComplex<T> z) {
  1802.         return createComplex(FastMath.copySign(getRealPart(), z.getRealPart()),
  1803.                              FastMath.copySign(getImaginaryPart(), z.getImaginaryPart()));
  1804.     }

  1805.     /** {@inheritDoc} */
  1806.     @Override
  1807.     public FieldComplex<T> copySign(double r) {
  1808.         return createComplex(FastMath.copySign(getRealPart(), r), FastMath.copySign(getImaginaryPart(), r));
  1809.     }

  1810.     /** {@inheritDoc} */
  1811.     @Override
  1812.     public FieldComplex<T> toDegrees() {
  1813.         return createComplex(FastMath.toDegrees(getRealPart()), FastMath.toDegrees(getImaginaryPart()));
  1814.     }

  1815.     /** {@inheritDoc} */
  1816.     @Override
  1817.     public FieldComplex<T> toRadians() {
  1818.         return createComplex(FastMath.toRadians(getRealPart()), FastMath.toRadians(getImaginaryPart()));
  1819.     }

  1820.     /** {@inheritDoc} */
  1821.     @Override
  1822.     public FieldComplex<T> getPi() {
  1823.         return getPi(getPartsField());
  1824.     }

  1825. }