View Javadoc
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  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.hipparchus.CalculusFieldElement;
23  import org.hipparchus.Field;
24  import org.hipparchus.exception.LocalizedCoreFormats;
25  import org.hipparchus.exception.MathIllegalArgumentException;
26  import org.hipparchus.exception.NullArgumentException;
27  import org.hipparchus.util.FastMath;
28  import org.hipparchus.util.FieldSinCos;
29  import org.hipparchus.util.FieldSinhCosh;
30  import org.hipparchus.util.MathArrays;
31  import org.hipparchus.util.MathUtils;
32  import org.hipparchus.util.Precision;
33  
34  /**
35   * Representation of a Complex number, i.e. a number which has both a
36   * real and imaginary part.
37   * <p>
38   * Implementations of arithmetic operations handle {@code NaN} and
39   * infinite values according to the rules for {@link java.lang.Double}, i.e.
40   * {@link #equals} is an equivalence relation for all instances that have
41   * a {@code NaN} in either real or imaginary part, e.g. the following are
42   * considered equal:
43   * <ul>
44   *  <li>{@code 1 + NaNi}</li>
45   *  <li>{@code NaN + i}</li>
46   *  <li>{@code NaN + NaNi}</li>
47   * </ul>
48   * <p>
49   * Note that this contradicts the IEEE-754 standard for floating
50   * point numbers (according to which the test {@code x == x} must fail if
51   * {@code x} is {@code NaN}). The method
52   * {@link org.hipparchus.util.Precision#equals(double,double,int)
53   * equals for primitive double} in {@link org.hipparchus.util.Precision}
54   * conforms with IEEE-754 while this class conforms with the standard behavior
55   * for Java object types.
56   * @param <T> the type of the field elements
57   * @since 2.0
58   */
59  public class FieldComplex<T extends CalculusFieldElement<T>> implements CalculusFieldElement<FieldComplex<T>>  {
60  
61      /** A real number representing log(10). */
62      private static final double LOG10 = 2.302585092994045684;
63  
64      /** The imaginary part. */
65      private final T imaginary;
66  
67      /** The real part. */
68      private final T real;
69  
70      /** Record whether this complex number is equal to NaN. */
71      private final transient boolean isNaN;
72  
73      /** Record whether this complex number is infinite. */
74      private final transient boolean isInfinite;
75  
76      /**
77       * Create a complex number given only the real part.
78       *
79       * @param real Real part.
80       */
81      public FieldComplex(T real) {
82          this(real, real.getField().getZero());
83      }
84  
85      /**
86       * Create a complex number given the real and imaginary parts.
87       *
88       * @param real Real part.
89       * @param imaginary Imaginary part.
90       */
91      public FieldComplex(T real, T imaginary) {
92          this.real = real;
93          this.imaginary = imaginary;
94  
95          isNaN = real.isNaN() || imaginary.isNaN();
96          isInfinite = !isNaN &&
97              (real.isInfinite() || imaginary.isInfinite());
98      }
99  
100     /** Get the square root of -1.
101      * @param field field the complex components belong to
102      * @return number representing "0.0 + 1.0i"
103      * @param <T> the type of the field elements
104      */
105     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getI(final Field<T> field) {
106         return new FieldComplex<>(field.getZero(), field.getOne());
107     }
108 
109     /** Get the square root of -1.
110      * @param field field the complex components belong to
111      * @return number representing "0.0 _ 1.0i"
112      * @param <T> the type of the field elements
113      */
114     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getMinusI(final Field<T> field) {
115         return new FieldComplex<>(field.getZero(), field.getOne().negate());
116     }
117 
118     /** Get a complex number representing "NaN + NaNi".
119      * @param field field the complex components belong to
120      * @return complex number representing "NaN + NaNi"
121      * @param <T> the type of the field elements
122      */
123     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getNaN(final Field<T> field) {
124         return new FieldComplex<>(field.getZero().add(Double.NaN), field.getZero().add(Double.NaN));
125     }
126 
127     /** Get a complex number representing "+INF + INFi".
128      * @param field field the complex components belong to
129      * @return complex number representing "+INF + INFi"
130      * @param <T> the type of the field elements
131      */
132     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getInf(final Field<T> field) {
133         return new FieldComplex<>(field.getZero().add(Double.POSITIVE_INFINITY), field.getZero().add(Double.POSITIVE_INFINITY));
134     }
135 
136     /** Get a complex number representing "1.0 + 0.0i".
137      * @param field field the complex components belong to
138      * @return complex number representing "1.0 + 0.0i"
139      * @param <T> the type of the field elements
140      */
141     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getOne(final Field<T> field) {
142         return new FieldComplex<>(field.getOne(), field.getZero());
143     }
144 
145     /** Get a complex number representing "-1.0 + 0.0i".
146      * @param field field the complex components belong to
147      * @return complex number representing "-1.0 + 0.0i"
148      * @param <T> the type of the field elements
149      */
150     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getMinusOne(final Field<T> field) {
151         return new FieldComplex<>(field.getOne().negate(), field.getZero());
152     }
153 
154     /** Get a complex number representing "0.0 + 0.0i".
155      * @param field field the complex components belong to
156      * @return complex number representing "0.0 + 0.0i
157      * @param <T> the type of the field elements
158      */
159     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getZero(final Field<T> field) {
160         return new FieldComplex<>(field.getZero(), field.getZero());
161     }
162 
163     /** Get a complex number representing "π + 0.0i".
164      * @param field field the complex components belong to
165      * @return complex number representing "π + 0.0i
166      * @param <T> the type of the field elements
167      */
168     public static <T extends CalculusFieldElement<T>> FieldComplex<T> getPi(final Field<T> field) {
169         return new FieldComplex<>(field.getZero().getPi(), field.getZero());
170     }
171 
172     /**
173      * Return the absolute value of this complex number.
174      * Returns {@code NaN} if either real or imaginary part is {@code NaN}
175      * and {@code Double.POSITIVE_INFINITY} if neither part is {@code NaN},
176      * but at least one part is infinite.
177      *
178      * @return the absolute value.
179      */
180     @Override
181     public FieldComplex<T> abs() {
182         // we check NaN here because FastMath.hypot checks it after infinity
183         return isNaN ? getNaN(getPartsField()) : createComplex(FastMath.hypot(real, imaginary), getPartsField().getZero());
184     }
185 
186     /**
187      * Returns a {@code Complex} whose value is
188      * {@code (this + addend)}.
189      * Uses the definitional formula
190      * <p>
191      *   {@code (a + bi) + (c + di) = (a+c) + (b+d)i}
192      * </p>
193      * If either {@code this} or {@code addend} has a {@code NaN} value in
194      * either part, {@link #getNaN(Field)} is returned; otherwise {@code Infinite}
195      * and {@code NaN} values are returned in the parts of the result
196      * according to the rules for {@link java.lang.Double} arithmetic.
197      *
198      * @param  addend Value to be added to this {@code Complex}.
199      * @return {@code this + addend}.
200      * @throws NullArgumentException if {@code addend} is {@code null}.
201      */
202     @Override
203     public FieldComplex<T> add(FieldComplex<T> addend) throws NullArgumentException {
204         MathUtils.checkNotNull(addend);
205         if (isNaN || addend.isNaN) {
206             return getNaN(getPartsField());
207         }
208 
209         return createComplex(real.add(addend.getRealPart()),
210                              imaginary.add(addend.getImaginaryPart()));
211     }
212 
213     /**
214      * Returns a {@code Complex} whose value is {@code (this + addend)},
215      * with {@code addend} interpreted as a real number.
216      *
217      * @param addend Value to be added to this {@code Complex}.
218      * @return {@code this + addend}.
219      * @see #add(FieldComplex)
220      */
221     public FieldComplex<T> add(T addend) {
222         if (isNaN || addend.isNaN()) {
223             return getNaN(getPartsField());
224         }
225 
226         return createComplex(real.add(addend), imaginary);
227     }
228 
229     /**
230      * Returns a {@code Complex} whose value is {@code (this + addend)},
231      * with {@code addend} interpreted as a real number.
232      *
233      * @param addend Value to be added to this {@code Complex}.
234      * @return {@code this + addend}.
235      * @see #add(FieldComplex)
236      */
237     @Override
238     public FieldComplex<T> add(double addend) {
239         if (isNaN || Double.isNaN(addend)) {
240             return getNaN(getPartsField());
241         }
242 
243         return createComplex(real.add(addend), imaginary);
244     }
245 
246     /**
247      * Returns the conjugate of this complex number.
248      * The conjugate of {@code a + bi} is {@code a - bi}.
249      * <p>
250      * {@link #getNaN(Field)} is returned if either the real or imaginary
251      * part of this Complex number equals {@code Double.NaN}.
252      * </p><p>
253      * If the imaginary part is infinite, and the real part is not
254      * {@code NaN}, the returned value has infinite imaginary part
255      * of the opposite sign, e.g. the conjugate of
256      * {@code 1 + POSITIVE_INFINITY i} is {@code 1 - NEGATIVE_INFINITY i}.
257      * </p>
258      * @return the conjugate of this Complex object.
259      */
260     public FieldComplex<T> conjugate() {
261         if (isNaN) {
262             return getNaN(getPartsField());
263         }
264 
265         return createComplex(real, imaginary.negate());
266     }
267 
268     /**
269      * Returns a {@code Complex} whose value is
270      * {@code (this / divisor)}.
271      * Implements the definitional formula
272      * <pre>
273      *  <code>
274      *    a + bi          ac + bd + (bc - ad)i
275      *    ----------- = -------------------------
276      *    c + di         c<sup>2</sup> + d<sup>2</sup>
277      *  </code>
278      * </pre>
279      * but uses
280      * <a href="http://doi.acm.org/10.1145/1039813.1039814">
281      * prescaling of operands</a> to limit the effects of overflows and
282      * underflows in the computation.
283      * <p>
284      * {@code Infinite} and {@code NaN} values are handled according to the
285      * following rules, applied in the order presented:
286      * <ul>
287      *  <li>If either {@code this} or {@code divisor} has a {@code NaN} value
288      *   in either part, {@link #getNaN(Field)} is returned.
289      *  </li>
290      *  <li>If {@code divisor} equals {@link #getZero(Field)}, {@link #getNaN(Field)} is returned.
291      *  </li>
292      *  <li>If {@code this} and {@code divisor} are both infinite,
293      *   {@link #getNaN(Field)} is returned.
294      *  </li>
295      *  <li>If {@code this} is finite (i.e., has no {@code Infinite} or
296      *   {@code NaN} parts) and {@code divisor} is infinite (one or both parts
297      *   infinite), {@link #getZero(Field)} is returned.
298      *  </li>
299      *  <li>If {@code this} is infinite and {@code divisor} is finite,
300      *   {@code NaN} values are returned in the parts of the result if the
301      *   {@link java.lang.Double} rules applied to the definitional formula
302      *   force {@code NaN} results.
303      *  </li>
304      * </ul>
305      *
306      * @param divisor Value by which this {@code Complex} is to be divided.
307      * @return {@code this / divisor}.
308      * @throws NullArgumentException if {@code divisor} is {@code null}.
309      */
310     @Override
311     public FieldComplex<T> divide(FieldComplex<T> divisor)
312         throws NullArgumentException {
313         MathUtils.checkNotNull(divisor);
314         if (isNaN || divisor.isNaN) {
315             return getNaN(getPartsField());
316         }
317 
318         final T c = divisor.getRealPart();
319         final T d = divisor.getImaginaryPart();
320         if (c.isZero() && d.isZero()) {
321             return getNaN(getPartsField());
322         }
323 
324         if (divisor.isInfinite() && !isInfinite()) {
325             return getZero(getPartsField());
326         }
327 
328         if (FastMath.abs(c).getReal() < FastMath.abs(d).getReal()) {
329             T q = c.divide(d);
330             T invDen = c.multiply(q).add(d).reciprocal();
331             return createComplex(real.multiply(q).add(imaginary).multiply(invDen),
332                                  imaginary.multiply(q).subtract(real).multiply(invDen));
333         } else {
334             T q = d.divide(c);
335             T invDen = d.multiply(q).add(c).reciprocal();
336             return createComplex(imaginary.multiply(q).add(real).multiply(invDen),
337                                  imaginary.subtract(real.multiply(q)).multiply(invDen));
338         }
339     }
340 
341     /**
342      * Returns a {@code Complex} whose value is {@code (this / divisor)},
343      * with {@code divisor} interpreted as a real number.
344      *
345      * @param  divisor Value by which this {@code Complex} is to be divided.
346      * @return {@code this / divisor}.
347      * @see #divide(FieldComplex)
348      */
349     public FieldComplex<T> divide(T divisor) {
350         if (isNaN || divisor.isNaN()) {
351             return getNaN(getPartsField());
352         }
353         if (divisor.isZero()) {
354             return getNaN(getPartsField());
355         }
356         if (divisor.isInfinite()) {
357             return !isInfinite() ? getZero(getPartsField()) : getNaN(getPartsField());
358         }
359         return createComplex(real.divide(divisor), imaginary.divide(divisor));
360     }
361 
362     /**
363      * Returns a {@code Complex} whose value is {@code (this / divisor)},
364      * with {@code divisor} interpreted as a real number.
365      *
366      * @param  divisor Value by which this {@code Complex} is to be divided.
367      * @return {@code this / divisor}.
368      * @see #divide(FieldComplex)
369      */
370     @Override
371     public FieldComplex<T> divide(double divisor) {
372         if (isNaN || Double.isNaN(divisor)) {
373             return getNaN(getPartsField());
374         }
375         if (divisor == 0.0) {
376             return getNaN(getPartsField());
377         }
378         if (Double.isInfinite(divisor)) {
379             return !isInfinite() ? getZero(getPartsField()) : getNaN(getPartsField());
380         }
381         return createComplex(real.divide(divisor), imaginary.divide(divisor));
382     }
383 
384     /** {@inheritDoc} */
385     @Override
386     public FieldComplex<T> reciprocal() {
387         if (isNaN) {
388             return getNaN(getPartsField());
389         }
390 
391         if (real.isZero() && imaginary.isZero()) {
392             return getInf(getPartsField());
393         }
394 
395         if (isInfinite) {
396             return getZero(getPartsField());
397         }
398 
399         if (FastMath.abs(real).getReal() < FastMath.abs(imaginary).getReal()) {
400             T q = real.divide(imaginary);
401             T scale = real.multiply(q).add(imaginary).reciprocal();
402             return createComplex(scale.multiply(q), scale.negate());
403         } else {
404             T q = imaginary.divide(real);
405             T scale = imaginary.multiply(q).add(real).reciprocal();
406             return createComplex(scale, scale.negate().multiply(q));
407         }
408     }
409 
410     /**
411      * Test for equality with another object.
412      * If both the real and imaginary parts of two complex numbers
413      * are exactly the same, and neither is {@code Double.NaN}, the two
414      * Complex objects are considered to be equal.
415      * The behavior is the same as for JDK's {@link Double#equals(Object)
416      * Double}:
417      * <ul>
418      *  <li>All {@code NaN} values are considered to be equal,
419      *   i.e, if either (or both) real and imaginary parts of the complex
420      *   number are equal to {@code Double.NaN}, the complex number is equal
421      *   to {@code NaN}.
422      *  </li>
423      *  <li>
424      *   Instances constructed with different representations of zero (i.e.
425      *   either "0" or "-0") are <em>not</em> considered to be equal.
426      *  </li>
427      * </ul>
428      *
429      * @param other Object to test for equality with this instance.
430      * @return {@code true} if the objects are equal, {@code false} if object
431      * is {@code null}, not an instance of {@code Complex}, or not equal to
432      * this instance.
433      */
434     @Override
435     public boolean equals(Object other) {
436         if (this == other) {
437             return true;
438         }
439         if (other instanceof FieldComplex){
440             @SuppressWarnings("unchecked")
441             FieldComplex<T> c = (FieldComplex<T>) other;
442             if (c.isNaN) {
443                 return isNaN;
444             } else {
445                 return real.equals(c.real) && imaginary.equals(c.imaginary);
446             }
447         }
448         return false;
449     }
450 
451     /**
452      * Test for the floating-point equality between Complex objects.
453      * It returns {@code true} if both arguments are equal or within the
454      * range of allowed error (inclusive).
455      *
456      * @param x First value (cannot be {@code null}).
457      * @param y Second value (cannot be {@code null}).
458      * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
459      * values between the real (resp. imaginary) parts of {@code x} and
460      * {@code y}.
461      * @param <T> the type of the field elements
462      * @return {@code true} if there are fewer than {@code maxUlps} floating
463      * point values between the real (resp. imaginary) parts of {@code x}
464      * and {@code y}.
465      *
466      * @see Precision#equals(double,double,int)
467      */
468     public static <T extends CalculusFieldElement<T>>boolean equals(FieldComplex<T> x, FieldComplex<T> y, int maxUlps) {
469         return Precision.equals(x.real.getReal(), y.real.getReal(), maxUlps) &&
470                Precision.equals(x.imaginary.getReal(), y.imaginary.getReal(), maxUlps);
471     }
472 
473     /**
474      * Returns {@code true} iff the values are equal as defined by
475      * {@link #equals(FieldComplex,FieldComplex,int) equals(x, y, 1)}.
476      *
477      * @param x First value (cannot be {@code null}).
478      * @param y Second value (cannot be {@code null}).
479      * @param <T> the type of the field elements
480      * @return {@code true} if the values are equal.
481      */
482     public static <T extends CalculusFieldElement<T>>boolean equals(FieldComplex<T> x, FieldComplex<T> y) {
483         return equals(x, y, 1);
484     }
485 
486     /**
487      * Returns {@code true} if, both for the real part and for the imaginary
488      * part, there is no T value strictly between the arguments or the
489      * difference between them is within the range of allowed error
490      * (inclusive).  Returns {@code false} if either of the arguments is NaN.
491      *
492      * @param x First value (cannot be {@code null}).
493      * @param y Second value (cannot be {@code null}).
494      * @param eps Amount of allowed absolute error.
495      * @param <T> the type of the field elements
496      * @return {@code true} if the values are two adjacent floating point
497      * numbers or they are within range of each other.
498      *
499      * @see Precision#equals(double,double,double)
500      */
501     public static <T extends CalculusFieldElement<T>>boolean equals(FieldComplex<T> x, FieldComplex<T> y,
502                                                                     double eps) {
503         return Precision.equals(x.real.getReal(), y.real.getReal(), eps) &&
504                Precision.equals(x.imaginary.getReal(), y.imaginary.getReal(), eps);
505     }
506 
507     /**
508      * Returns {@code true} if, both for the real part and for the imaginary
509      * part, there is no T value strictly between the arguments or the
510      * relative difference between them is smaller or equal to the given
511      * tolerance. Returns {@code false} if either of the arguments is NaN.
512      *
513      * @param x First value (cannot be {@code null}).
514      * @param y Second value (cannot be {@code null}).
515      * @param eps Amount of allowed relative error.
516      * @param <T> the type of the field elements
517      * @return {@code true} if the values are two adjacent floating point
518      * numbers or they are within range of each other.
519      *
520      * @see Precision#equalsWithRelativeTolerance(double,double,double)
521      */
522     public static <T extends CalculusFieldElement<T>>boolean equalsWithRelativeTolerance(FieldComplex<T> x,
523                                                                                          FieldComplex<T> y,
524                                                                                          double eps) {
525         return Precision.equalsWithRelativeTolerance(x.real.getReal(), y.real.getReal(), eps) &&
526                Precision.equalsWithRelativeTolerance(x.imaginary.getReal(), y.imaginary.getReal(), eps);
527     }
528 
529     /**
530      * Get a hashCode for the complex number.
531      * Any {@code Double.NaN} value in real or imaginary part produces
532      * the same hash code {@code 7}.
533      *
534      * @return a hash code value for this object.
535      */
536     @Override
537     public int hashCode() {
538         if (isNaN) {
539             return 7;
540         }
541         return 37 * (17 * imaginary.hashCode() + real.hashCode());
542     }
543 
544     /** {@inheritDoc}
545      * <p>
546      * This implementation considers +0.0 and -0.0 to be equal for both
547      * real and imaginary components.
548      * </p>
549      */
550     @Override
551     public boolean isZero() {
552         return real.isZero() && imaginary.isZero();
553     }
554 
555     /**
556      * Access the imaginary part.
557      *
558      * @return the imaginary part.
559      */
560     public T getImaginary() {
561         return imaginary;
562     }
563 
564     /**
565      * Access the imaginary part.
566      *
567      * @return the imaginary part.
568      */
569     public T getImaginaryPart() {
570         return imaginary;
571     }
572 
573     /**
574      * Access the real part.
575      *
576      * @return the real part.
577      */
578     @Override
579     public double getReal() {
580         return real.getReal();
581     }
582 
583     /**
584      * Access the real part.
585      *
586      * @return the real part.
587      */
588     public T getRealPart() {
589         return real;
590     }
591 
592     /**
593      * Checks whether either or both parts of this complex number is
594      * {@code NaN}.
595      *
596      * @return true if either or both parts of this complex number is
597      * {@code NaN}; false otherwise.
598      */
599     @Override
600     public boolean isNaN() {
601         return isNaN;
602     }
603 
604     /** Check whether the instance is real (i.e. imaginary part is zero).
605      * @return true if imaginary part is zero
606       */
607     public boolean isReal() {
608         return imaginary.isZero();
609     }
610 
611     /** Check whether the instance is an integer (i.e. imaginary part is zero and real part has no fractional part).
612      * @return true if imaginary part is zero and real part has no fractional part
613      */
614     public boolean isMathematicalInteger() {
615         return isReal() && Precision.isMathematicalInteger(real.getReal());
616     }
617 
618     /**
619      * Checks whether either the real or imaginary part of this complex number
620      * takes an infinite value (either {@code Double.POSITIVE_INFINITY} or
621      * {@code Double.NEGATIVE_INFINITY}) and neither part
622      * is {@code NaN}.
623      *
624      * @return true if one or both parts of this complex number are infinite
625      * and neither part is {@code NaN}.
626      */
627     @Override
628     public boolean isInfinite() {
629         return isInfinite;
630     }
631 
632     /**
633      * Returns a {@code Complex} whose value is {@code this * factor}.
634      * Implements preliminary checks for {@code NaN} and infinity followed by
635      * the definitional formula:
636      * <p>
637      *   {@code (a + bi)(c + di) = (ac - bd) + (ad + bc)i}
638      * </p>
639      * Returns {@link #getNaN(Field)} if either {@code this} or {@code factor} has one or
640      * more {@code NaN} parts.
641      * <p>
642      * Returns {@link #getInf(Field)} if neither {@code this} nor {@code factor} has one
643      * or more {@code NaN} parts and if either {@code this} or {@code factor}
644      * has one or more infinite parts (same result is returned regardless of
645      * the sign of the components).
646      * </p><p>
647      * Returns finite values in components of the result per the definitional
648      * formula in all remaining cases.</p>
649      *
650      * @param  factor value to be multiplied by this {@code Complex}.
651      * @return {@code this * factor}.
652      * @throws NullArgumentException if {@code factor} is {@code null}.
653      */
654     @Override
655     public FieldComplex<T> multiply(FieldComplex<T> factor)
656         throws NullArgumentException {
657         MathUtils.checkNotNull(factor);
658         if (isNaN || factor.isNaN) {
659             return getNaN(getPartsField());
660         }
661         if (real.isInfinite() ||
662             imaginary.isInfinite() ||
663             factor.real.isInfinite() ||
664             factor.imaginary.isInfinite()) {
665             // we don't use isInfinite() to avoid testing for NaN again
666             return getInf(getPartsField());
667         }
668         return createComplex(real.linearCombination(real, factor.real, imaginary.negate(), factor.imaginary),
669                              real.linearCombination(real, factor.imaginary, imaginary, factor.real));
670     }
671 
672     /**
673      * Returns a {@code Complex} whose value is {@code this * factor}, with {@code factor}
674      * interpreted as a integer number.
675      *
676      * @param  factor value to be multiplied by this {@code Complex}.
677      * @return {@code this * factor}.
678      * @see #multiply(FieldComplex)
679      */
680     @Override
681     public FieldComplex<T> multiply(final int factor) {
682         if (isNaN) {
683             return getNaN(getPartsField());
684         }
685         if (real.isInfinite() || imaginary.isInfinite()) {
686             return getInf(getPartsField());
687         }
688         return createComplex(real.multiply(factor), imaginary.multiply(factor));
689     }
690 
691     /**
692      * Returns a {@code Complex} whose value is {@code this * factor}, with {@code factor}
693      * interpreted as a real number.
694      *
695      * @param  factor value to be multiplied by this {@code Complex}.
696      * @return {@code this * factor}.
697      * @see #multiply(FieldComplex)
698      */
699     @Override
700     public FieldComplex<T> multiply(double factor) {
701         if (isNaN || Double.isNaN(factor)) {
702             return getNaN(getPartsField());
703         }
704         if (real.isInfinite() ||
705             imaginary.isInfinite() ||
706             Double.isInfinite(factor)) {
707             // we don't use isInfinite() to avoid testing for NaN again
708             return getInf(getPartsField());
709         }
710         return createComplex(real.multiply(factor), imaginary.multiply(factor));
711     }
712 
713     /**
714      * Returns a {@code Complex} whose value is {@code this * factor}, with {@code factor}
715      * interpreted as a real number.
716      *
717      * @param  factor value to be multiplied by this {@code Complex}.
718      * @return {@code this * factor}.
719      * @see #multiply(FieldComplex)
720      */
721     public FieldComplex<T> multiply(T factor) {
722         if (isNaN || factor.isNaN()) {
723             return getNaN(getPartsField());
724         }
725         if (real.isInfinite() ||
726             imaginary.isInfinite() ||
727             factor.isInfinite()) {
728             // we don't use isInfinite() to avoid testing for NaN again
729             return getInf(getPartsField());
730         }
731         return createComplex(real.multiply(factor), imaginary.multiply(factor));
732     }
733 
734     /** Compute this * i.
735      * @return this * i
736      * @since 2.0
737      */
738     public FieldComplex<T> multiplyPlusI() {
739         return createComplex(imaginary.negate(), real);
740     }
741 
742     /** Compute this *- -i.
743      * @return this * i
744      * @since 2.0
745      */
746     public FieldComplex<T> multiplyMinusI() {
747         return createComplex(imaginary, real.negate());
748     }
749 
750     /**
751      * Returns a {@code Complex} whose value is {@code (-this)}.
752      * Returns {@code NaN} if either real or imaginary
753      * part of this Complex number is {@code Double.NaN}.
754      *
755      * @return {@code -this}.
756      */
757     @Override
758     public FieldComplex<T> negate() {
759         if (isNaN) {
760             return getNaN(getPartsField());
761         }
762 
763         return createComplex(real.negate(), imaginary.negate());
764     }
765 
766     /**
767      * Returns a {@code Complex} whose value is
768      * {@code (this - subtrahend)}.
769      * Uses the definitional formula
770      * <p>
771      *  {@code (a + bi) - (c + di) = (a-c) + (b-d)i}
772      * </p>
773      * If either {@code this} or {@code subtrahend} has a {@code NaN]} value in either part,
774      * {@link #getNaN(Field)} is returned; otherwise infinite and {@code NaN} values are
775      * returned in the parts of the result according to the rules for
776      * {@link java.lang.Double} arithmetic.
777      *
778      * @param  subtrahend value to be subtracted from this {@code Complex}.
779      * @return {@code this - subtrahend}.
780      * @throws NullArgumentException if {@code subtrahend} is {@code null}.
781      */
782     @Override
783     public FieldComplex<T> subtract(FieldComplex<T> subtrahend)
784         throws NullArgumentException {
785         MathUtils.checkNotNull(subtrahend);
786         if (isNaN || subtrahend.isNaN) {
787             return getNaN(getPartsField());
788         }
789 
790         return createComplex(real.subtract(subtrahend.getRealPart()),
791                              imaginary.subtract(subtrahend.getImaginaryPart()));
792     }
793 
794     /**
795      * Returns a {@code Complex} whose value is
796      * {@code (this - subtrahend)}.
797      *
798      * @param  subtrahend value to be subtracted from this {@code Complex}.
799      * @return {@code this - subtrahend}.
800      * @see #subtract(FieldComplex)
801      */
802     @Override
803     public FieldComplex<T> subtract(double subtrahend) {
804         if (isNaN || Double.isNaN(subtrahend)) {
805             return getNaN(getPartsField());
806         }
807         return createComplex(real.subtract(subtrahend), imaginary);
808     }
809 
810     /**
811      * Returns a {@code Complex} whose value is
812      * {@code (this - subtrahend)}.
813      *
814      * @param  subtrahend value to be subtracted from this {@code Complex}.
815      * @return {@code this - subtrahend}.
816      * @see #subtract(FieldComplex)
817      */
818     public FieldComplex<T> subtract(T subtrahend) {
819         if (isNaN || subtrahend.isNaN()) {
820             return getNaN(getPartsField());
821         }
822         return createComplex(real.subtract(subtrahend), imaginary);
823     }
824 
825     /**
826      * Compute the
827      * <a href="http://mathworld.wolfram.com/InverseCosine.html" TARGET="_top">
828      * inverse cosine</a> of this complex number.
829      * Implements the formula:
830      * <p>
831      *  {@code acos(z) = -i (log(z + i (sqrt(1 - z<sup>2</sup>))))}
832      * </p>
833      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
834      * input argument is {@code NaN} or infinite.
835      *
836      * @return the inverse cosine of this complex number.
837      */
838     @Override
839     public FieldComplex<T> acos() {
840         if (isNaN) {
841             return getNaN(getPartsField());
842         }
843 
844         return this.add(this.sqrt1z().multiplyPlusI()).log().multiplyMinusI();
845     }
846 
847     /**
848      * Compute the
849      * <a href="http://mathworld.wolfram.com/InverseSine.html" TARGET="_top">
850      * inverse sine</a> of this complex number.
851      * Implements the formula:
852      * <p>
853      *  {@code asin(z) = -i (log(sqrt(1 - z<sup>2</sup>) + iz))}
854      * </p><p>
855      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
856      * input argument is {@code NaN} or infinite.</p>
857      *
858      * @return the inverse sine of this complex number.
859      */
860     @Override
861     public FieldComplex<T> asin() {
862         if (isNaN) {
863             return getNaN(getPartsField());
864         }
865 
866         return sqrt1z().add(this.multiplyPlusI()).log().multiplyMinusI();
867     }
868 
869     /**
870      * Compute the
871      * <a href="http://mathworld.wolfram.com/InverseTangent.html" TARGET="_top">
872      * inverse tangent</a> of this complex number.
873      * Implements the formula:
874      * <p>
875      * {@code atan(z) = (i/2) log((1 - iz)/(1 + iz))}
876      * </p><p>
877      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
878      * input argument is {@code NaN} or infinite.</p>
879      *
880      * @return the inverse tangent of this complex number
881      */
882     @Override
883     public FieldComplex<T> atan() {
884         if (isNaN) {
885             return getNaN(getPartsField());
886         }
887 
888         final T one = getPartsField().getOne();
889         if (real.isZero()) {
890 
891             // singularity at ±i
892             if (imaginary.multiply(imaginary).subtract(one).isZero()) {
893                 return getNaN(getPartsField());
894             }
895 
896             // branch cut on imaginary axis
897             final T zero = getPartsField().getZero();
898             final FieldComplex<T> tmp = createComplex(one.add(imaginary).divide(one.subtract(imaginary)), zero).
899                                         log().multiplyPlusI().multiply(0.5);
900             return createComplex(FastMath.copySign(tmp.real, real), tmp.imaginary);
901 
902         } else {
903             // regular formula
904             final FieldComplex<T> n = createComplex(one.add(imaginary), real.negate());
905             final FieldComplex<T> d = createComplex(one.subtract(imaginary),  real);
906             return n.divide(d).log().multiplyPlusI().multiply(0.5);
907         }
908 
909     }
910 
911     /**
912      * Compute the
913      * <a href="http://mathworld.wolfram.com/Cosine.html" TARGET="_top">
914      * cosine</a> of this complex number.
915      * Implements the formula:
916      * <p>
917      *  {@code cos(a + bi) = cos(a)cosh(b) - sin(a)sinh(b)i}
918      * </p><p>
919      * where the (real) functions on the right-hand side are
920      * {@link FastMath#sin}, {@link FastMath#cos},
921      * {@link FastMath#cosh} and {@link FastMath#sinh}.
922      * </p><p>
923      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
924      * input argument is {@code NaN}.
925      * </p><p>
926      * Infinite values in real or imaginary parts of the input may result in
927      * infinite or NaN values returned in parts of the result.</p>
928      * <pre>
929      *  Examples:
930      *  <code>
931      *   cos(1 &plusmn; INFINITY i) = 1 \u2213 INFINITY i
932      *   cos(&plusmn;INFINITY + i) = NaN + NaN i
933      *   cos(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
934      *  </code>
935      * </pre>
936      *
937      * @return the cosine of this complex number.
938      */
939     @Override
940     public FieldComplex<T> cos() {
941         if (isNaN) {
942             return getNaN(getPartsField());
943         }
944 
945         final FieldSinCos<T>   scr  = FastMath.sinCos(real);
946         final FieldSinhCosh<T> schi = FastMath.sinhCosh(imaginary);
947         return createComplex(scr.cos().multiply(schi.cosh()), scr.sin().negate().multiply(schi.sinh()));
948     }
949 
950     /**
951      * Compute the
952      * <a href="http://mathworld.wolfram.com/HyperbolicCosine.html" TARGET="_top">
953      * hyperbolic cosine</a> of this complex number.
954      * Implements the formula:
955      * <pre>
956      *  <code>
957      *   cosh(a + bi) = cosh(a)cos(b) + sinh(a)sin(b)i
958      *  </code>
959      * </pre>
960      * where the (real) functions on the right-hand side are
961      * {@link FastMath#sin}, {@link FastMath#cos},
962      * {@link FastMath#cosh} and {@link FastMath#sinh}.
963      * <p>
964      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
965      * input argument is {@code NaN}.
966      * </p>
967      * Infinite values in real or imaginary parts of the input may result in
968      * infinite or NaN values returned in parts of the result.
969      * <pre>
970      *  Examples:
971      *  <code>
972      *   cosh(1 &plusmn; INFINITY i) = NaN + NaN i
973      *   cosh(&plusmn;INFINITY + i) = INFINITY &plusmn; INFINITY i
974      *   cosh(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
975      *  </code>
976      * </pre>
977      *
978      * @return the hyperbolic cosine of this complex number.
979      */
980     @Override
981     public FieldComplex<T> cosh() {
982         if (isNaN) {
983             return getNaN(getPartsField());
984         }
985 
986         final FieldSinhCosh<T> schr = FastMath.sinhCosh(real);
987         final FieldSinCos<T>   sci  = FastMath.sinCos(imaginary);
988         return createComplex(schr.cosh().multiply(sci.cos()), schr.sinh().multiply(sci.sin()));
989     }
990 
991     /**
992      * Compute the
993      * <a href="http://mathworld.wolfram.com/ExponentialFunction.html" TARGET="_top">
994      * exponential function</a> of this complex number.
995      * Implements the formula:
996      * <pre>
997      *  <code>
998      *   exp(a + bi) = exp(a)cos(b) + exp(a)sin(b)i
999      *  </code>
1000      * </pre>
1001      * where the (real) functions on the right-hand side are
1002      * {@link FastMath#exp}, {@link FastMath#cos}, and
1003      * {@link FastMath#sin}.
1004      * <p>
1005      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
1006      * input argument is {@code NaN}.
1007      * </p>
1008      * Infinite values in real or imaginary parts of the input may result in
1009      * infinite or NaN values returned in parts of the result.
1010      * <pre>
1011      *  Examples:
1012      *  <code>
1013      *   exp(1 &plusmn; INFINITY i) = NaN + NaN i
1014      *   exp(INFINITY + i) = INFINITY + INFINITY i
1015      *   exp(-INFINITY + i) = 0 + 0i
1016      *   exp(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
1017      *  </code>
1018      * </pre>
1019      *
1020      * @return <code><i>e</i><sup>this</sup></code>.
1021      */
1022     @Override
1023     public FieldComplex<T> exp() {
1024         if (isNaN) {
1025             return getNaN(getPartsField());
1026         }
1027 
1028         final T              expReal = FastMath.exp(real);
1029         final FieldSinCos<T> sc      = FastMath.sinCos(imaginary);
1030         return createComplex(expReal.multiply(sc.cos()), expReal.multiply(sc.sin()));
1031     }
1032 
1033     /** {@inheritDoc} */
1034     @Override
1035     public FieldComplex<T> expm1() {
1036         if (isNaN) {
1037             return getNaN(getPartsField());
1038         }
1039 
1040         final T              expm1Real = FastMath.expm1(real);
1041         final FieldSinCos<T> sc        = FastMath.sinCos(imaginary);
1042         return createComplex(expm1Real.multiply(sc.cos()), expm1Real.multiply(sc.sin()));
1043     }
1044 
1045     /**
1046      * Compute the
1047      * <a href="http://mathworld.wolfram.com/NaturalLogarithm.html" TARGET="_top">
1048      * natural logarithm</a> of this complex number.
1049      * Implements the formula:
1050      * <pre>
1051      *  <code>
1052      *   log(a + bi) = ln(|a + bi|) + arg(a + bi)i
1053      *  </code>
1054      * </pre>
1055      * where ln on the right hand side is {@link FastMath#log},
1056      * {@code |a + bi|} is the modulus, {@link #abs},  and
1057      * {@code arg(a + bi) = }{@link FastMath#atan2}(b, a).
1058      * <p>
1059      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
1060      * input argument is {@code NaN}.
1061      * </p>
1062      * Infinite (or critical) values in real or imaginary parts of the input may
1063      * result in infinite or NaN values returned in parts of the result.
1064      * <pre>
1065      *  Examples:
1066      *  <code>
1067      *   log(1 &plusmn; INFINITY i) = INFINITY &plusmn; (&pi;/2)i
1068      *   log(INFINITY + i) = INFINITY + 0i
1069      *   log(-INFINITY + i) = INFINITY + &pi;i
1070      *   log(INFINITY &plusmn; INFINITY i) = INFINITY &plusmn; (&pi;/4)i
1071      *   log(-INFINITY &plusmn; INFINITY i) = INFINITY &plusmn; (3&pi;/4)i
1072      *   log(0 + 0i) = -INFINITY + 0i
1073      *  </code>
1074      * </pre>
1075      *
1076      * @return the value <code>ln &nbsp; this</code>, the natural logarithm
1077      * of {@code this}.
1078      */
1079     @Override
1080     public FieldComplex<T> log() {
1081         if (isNaN) {
1082             return getNaN(getPartsField());
1083         }
1084 
1085         return createComplex(FastMath.log(FastMath.hypot(real, imaginary)),
1086                              FastMath.atan2(imaginary, real));
1087     }
1088 
1089     /** {@inheritDoc} */
1090     @Override
1091     public FieldComplex<T> log1p() {
1092         return add(1.0).log();
1093     }
1094 
1095     /** {@inheritDoc} */
1096     @Override
1097     public FieldComplex<T> log10() {
1098         return log().divide(LOG10);
1099     }
1100 
1101     /**
1102      * Returns of value of this complex number raised to the power of {@code x}.
1103      * <p>
1104      * If {@code x} is a real number whose real part has an integer value, returns {@link #pow(int)},
1105      * if both {@code this} and {@code x} are real and {@link FastMath#pow(double, double)}
1106      * with the corresponding real arguments would return a finite number (neither NaN
1107      * nor infinite), then returns the same value converted to {@code Complex},
1108      * with the same special cases.
1109      * In all other cases real cases, implements y<sup>x</sup> = exp(x&middot;log(y)).
1110      * </p>
1111      *
1112      * @param  x exponent to which this {@code Complex} is to be raised.
1113      * @return <code> this<sup>x</sup></code>.
1114      * @throws NullArgumentException if x is {@code null}.
1115      */
1116     @Override
1117     public FieldComplex<T> pow(FieldComplex<T> x)
1118         throws NullArgumentException {
1119 
1120         MathUtils.checkNotNull(x);
1121 
1122         if (x.imaginary.isZero()) {
1123             final int nx = (int) FastMath.rint(x.real.getReal());
1124             if (x.real.getReal() == nx) {
1125                 // integer power
1126                 return pow(nx);
1127             } else if (this.imaginary.isZero()) {
1128                 // check real implementation that handles a bunch of special cases
1129                 final T realPow = FastMath.pow(this.real, x.real);
1130                 if (realPow.isFinite()) {
1131                     return createComplex(realPow, getPartsField().getZero());
1132                 }
1133             }
1134         }
1135 
1136         // generic implementation
1137         return this.log().multiply(x).exp();
1138 
1139     }
1140 
1141 
1142     /**
1143      * Returns of value of this complex number raised to the power of {@code x}.
1144      * <p>
1145      * If {@code x} has an integer value, returns {@link #pow(int)},
1146      * if {@code this} is real and {@link FastMath#pow(double, double)}
1147      * with the corresponding real arguments would return a finite number (neither NaN
1148      * nor infinite), then returns the same value converted to {@code Complex},
1149      * with the same special cases.
1150      * In all other cases real cases, implements y<sup>x</sup> = exp(x&middot;log(y)).
1151      * </p>
1152      *
1153      * @param  x exponent to which this {@code Complex} is to be raised.
1154      * @return <code> this<sup>x</sup></code>.
1155      */
1156     public FieldComplex<T> pow(T x) {
1157 
1158         final int nx = (int) FastMath.rint(x.getReal());
1159         if (x.getReal() == nx) {
1160             // integer power
1161             return pow(nx);
1162         } else if (this.imaginary.isZero()) {
1163             // check real implementation that handles a bunch of special cases
1164             final T realPow = FastMath.pow(this.real, x);
1165             if (realPow.isFinite()) {
1166                 return createComplex(realPow, getPartsField().getZero());
1167             }
1168         }
1169 
1170         // generic implementation
1171         return this.log().multiply(x).exp();
1172 
1173     }
1174 
1175     /**
1176      * Returns of value of this complex number raised to the power of {@code x}.
1177      * <p>
1178      * If {@code x} has an integer value, returns {@link #pow(int)},
1179      * if {@code this} is real and {@link FastMath#pow(double, double)}
1180      * with the corresponding real arguments would return a finite number (neither NaN
1181      * nor infinite), then returns the same value converted to {@code Complex},
1182      * with the same special cases.
1183      * In all other cases real cases, implements y<sup>x</sup> = exp(x&middot;log(y)).
1184      * </p>
1185      *
1186      * @param  x exponent to which this {@code Complex} is to be raised.
1187      * @return <code> this<sup>x</sup></code>.
1188      */
1189     @Override
1190     public FieldComplex<T> pow(double x) {
1191 
1192         final int nx = (int) FastMath.rint(x);
1193         if (x == nx) {
1194             // integer power
1195             return pow(nx);
1196         } else if (this.imaginary.isZero()) {
1197             // check real implementation that handles a bunch of special cases
1198             final T realPow = FastMath.pow(this.real, x);
1199             if (realPow.isFinite()) {
1200                 return createComplex(realPow, getPartsField().getZero());
1201             }
1202         }
1203 
1204         // generic implementation
1205         return this.log().multiply(x).exp();
1206 
1207     }
1208 
1209      /** {@inheritDoc} */
1210     @Override
1211     public FieldComplex<T> pow(final int n) {
1212 
1213         FieldComplex<T> result = getField().getOne();
1214         final boolean invert;
1215         int p = n;
1216         if (p < 0) {
1217             invert = true;
1218             p = -p;
1219         } else {
1220             invert = false;
1221         }
1222 
1223         // Exponentiate by successive squaring
1224         FieldComplex<T> square = this;
1225         while (p > 0) {
1226             if ((p & 0x1) > 0) {
1227                 result = result.multiply(square);
1228             }
1229             square = square.multiply(square);
1230             p = p >> 1;
1231         }
1232 
1233         return invert ? result.reciprocal() : result;
1234 
1235     }
1236 
1237      /**
1238       * Compute the
1239      * <a href="http://mathworld.wolfram.com/Sine.html" TARGET="_top">
1240      * sine</a>
1241      * of this complex number.
1242      * Implements the formula:
1243      * <pre>
1244      *  <code>
1245      *   sin(a + bi) = sin(a)cosh(b) + cos(a)sinh(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 {@code NaN} values returned in parts of the result.
1257      * <pre>
1258      *  Examples:
1259      *  <code>
1260      *   sin(1 &plusmn; INFINITY i) = 1 &plusmn; INFINITY i
1261      *   sin(&plusmn;INFINITY + i) = NaN + NaN i
1262      *   sin(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
1263      *  </code>
1264      * </pre>
1265      *
1266      * @return the sine of this complex number.
1267      */
1268     @Override
1269     public FieldComplex<T> sin() {
1270         if (isNaN) {
1271             return getNaN(getPartsField());
1272         }
1273 
1274         final FieldSinCos<T>   scr  = FastMath.sinCos(real);
1275         final FieldSinhCosh<T> schi = FastMath.sinhCosh(imaginary);
1276         return createComplex(scr.sin().multiply(schi.cosh()), scr.cos().multiply(schi.sinh()));
1277 
1278     }
1279 
1280     /** {@inheritDoc}
1281      */
1282     @Override
1283     public FieldSinCos<FieldComplex<T>> sinCos() {
1284         if (isNaN) {
1285             return new FieldSinCos<>(getNaN(getPartsField()), getNaN(getPartsField()));
1286         }
1287 
1288         final FieldSinCos<T>   scr = FastMath.sinCos(real);
1289         final FieldSinhCosh<T> schi = FastMath.sinhCosh(imaginary);
1290         return new FieldSinCos<>(createComplex(scr.sin().multiply(schi.cosh()), scr.cos().multiply(schi.sinh())),
1291                                  createComplex(scr.cos().multiply(schi.cosh()), scr.sin().negate().multiply(schi.sinh())));
1292     }
1293 
1294     /** {@inheritDoc} */
1295     @Override
1296     public FieldComplex<T> atan2(FieldComplex<T> x) {
1297 
1298         // compute r = sqrt(x^2+y^2)
1299         final FieldComplex<T> r = x.multiply(x).add(multiply(this)).sqrt();
1300 
1301         if (x.real.getReal() >= 0) {
1302             // compute atan2(y, x) = 2 atan(y / (r + x))
1303             return divide(r.add(x)).atan().multiply(2);
1304         } else {
1305             // compute atan2(y, x) = +/- pi - 2 atan(y / (r - x))
1306             return divide(r.subtract(x)).atan().multiply(-2).add(x.real.getPi());
1307         }
1308     }
1309 
1310     /** {@inheritDoc}
1311      * <p>
1312      * Branch cuts are on the real axis, below +1.
1313      * </p>
1314      */
1315     @Override
1316     public FieldComplex<T> acosh() {
1317         final FieldComplex<T> sqrtPlus  = add(1).sqrt();
1318         final FieldComplex<T> sqrtMinus = subtract(1).sqrt();
1319         return add(sqrtPlus.multiply(sqrtMinus)).log();
1320     }
1321 
1322     /** {@inheritDoc}
1323      * <p>
1324      * Branch cuts are on the imaginary axis, above +i and below -i.
1325      * </p>
1326      */
1327     @Override
1328     public FieldComplex<T> asinh() {
1329         return add(multiply(this).add(1.0).sqrt()).log();
1330     }
1331 
1332     /** {@inheritDoc}
1333      * <p>
1334      * Branch cuts are on the real axis, above +1 and below -1.
1335      * </p>
1336      */
1337     @Override
1338     public FieldComplex<T> atanh() {
1339         final FieldComplex<T> logPlus  = add(1).log();
1340         final FieldComplex<T> logMinus = createComplex(getPartsField().getOne().subtract(real), imaginary.negate()).log();
1341         return logPlus.subtract(logMinus).multiply(0.5);
1342     }
1343 
1344     /**
1345      * Compute the
1346      * <a href="http://mathworld.wolfram.com/HyperbolicSine.html" TARGET="_top">
1347      * hyperbolic sine</a> of this complex number.
1348      * Implements the formula:
1349      * <pre>
1350      *  <code>
1351      *   sinh(a + bi) = sinh(a)cos(b)) + cosh(a)sin(b)i
1352      *  </code>
1353      * </pre>
1354      * where the (real) functions on the right-hand side are
1355      * {@link FastMath#sin}, {@link FastMath#cos},
1356      * {@link FastMath#cosh} and {@link FastMath#sinh}.
1357      * <p>
1358      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
1359      * input argument is {@code NaN}.
1360      * </p><p>
1361      * Infinite values in real or imaginary parts of the input may result in
1362      * infinite or NaN values returned in parts of the result.
1363      * <pre>
1364      *  Examples:
1365      *  <code>
1366      *   sinh(1 &plusmn; INFINITY i) = NaN + NaN i
1367      *   sinh(&plusmn;INFINITY + i) = &plusmn; INFINITY + INFINITY i
1368      *   sinh(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
1369      *  </code>
1370      * </pre>
1371      *
1372      * @return the hyperbolic sine of {@code this}.
1373      */
1374     @Override
1375     public FieldComplex<T> sinh() {
1376         if (isNaN) {
1377             return getNaN(getPartsField());
1378         }
1379 
1380         final FieldSinhCosh<T> schr = FastMath.sinhCosh(real);
1381         final FieldSinCos<T>   sci  = FastMath.sinCos(imaginary);
1382         return createComplex(schr.sinh().multiply(sci.cos()), schr.cosh().multiply(sci.sin()));
1383     }
1384 
1385     /** {@inheritDoc}
1386      */
1387     @Override
1388     public FieldSinhCosh<FieldComplex<T>> sinhCosh() {
1389         if (isNaN) {
1390             return new FieldSinhCosh<>(getNaN(getPartsField()), getNaN(getPartsField()));
1391         }
1392 
1393         final FieldSinhCosh<T> schr = FastMath.sinhCosh(real);
1394         final FieldSinCos<T>   sci  = FastMath.sinCos(imaginary);
1395         return new FieldSinhCosh<>(createComplex(schr.sinh().multiply(sci.cos()), schr.cosh().multiply(sci.sin())),
1396                                    createComplex(schr.cosh().multiply(sci.cos()), schr.sinh().multiply(sci.sin())));
1397     }
1398 
1399     /**
1400      * Compute the
1401      * <a href="http://mathworld.wolfram.com/SquareRoot.html" TARGET="_top">
1402      * square root</a> of this complex number.
1403      * Implements the following algorithm to compute {@code sqrt(a + bi)}:
1404      * <ol><li>Let {@code t = sqrt((|a| + |a + bi|) / 2)}</li>
1405      * <li><pre>if {@code  a ≥ 0} return {@code t + (b/2t)i}
1406      *  else return {@code |b|/2t + sign(b)t i }</pre></li>
1407      * </ol>
1408      * where <ul>
1409      * <li>{@code |a| = }{@link FastMath#abs(CalculusFieldElement) abs(a)}</li>
1410      * <li>{@code |a + bi| = }{@link FastMath#hypot(CalculusFieldElement, CalculusFieldElement) hypot(a, b)}</li>
1411      * <li>{@code sign(b) = }{@link FastMath#copySign(CalculusFieldElement, CalculusFieldElement) copySign(1, b)}
1412      * </ul>
1413      * The real part is therefore always nonnegative.
1414      * <p>
1415      * Returns {@link #getNaN(Field) NaN} if either real or imaginary part of the
1416      * input argument is {@code NaN}.
1417      * </p>
1418      * <p>
1419      * Infinite values in real or imaginary parts of the input may result in
1420      * infinite or NaN values returned in parts of the result.
1421      * </p>
1422      * <pre>
1423      *  Examples:
1424      *  <code>
1425      *   sqrt(1 ± ∞ i) = ∞ + NaN i
1426      *   sqrt(∞ + i) = ∞ + 0i
1427      *   sqrt(-∞ + i) = 0 + ∞ i
1428      *   sqrt(∞ ± ∞ i) = ∞ + NaN i
1429      *   sqrt(-∞ ± ∞ i) = NaN ± ∞ i
1430      *  </code>
1431      * </pre>
1432      *
1433      * @return the square root of {@code this} with nonnegative real part.
1434      */
1435     @Override
1436     public FieldComplex<T> sqrt() {
1437         if (isNaN) {
1438             return getNaN(getPartsField());
1439         }
1440 
1441         if (isZero()) {
1442             return getZero(getPartsField());
1443         }
1444 
1445         T t = FastMath.sqrt((FastMath.abs(real).add(FastMath.hypot(real, imaginary))).multiply(0.5));
1446         if (real.getReal() >= 0.0) {
1447             return createComplex(t, imaginary.divide(t.multiply(2)));
1448         } else {
1449             return createComplex(FastMath.abs(imaginary).divide(t.multiply(2)),
1450                                  FastMath.copySign(t, imaginary));
1451         }
1452     }
1453 
1454     /**
1455      * Compute the
1456      * <a href="http://mathworld.wolfram.com/SquareRoot.html" TARGET="_top">
1457      * square root</a> of <code>1 - this<sup>2</sup></code> for this complex
1458      * number.
1459      * Computes the result directly as
1460      * {@code sqrt(ONE.subtract(z.multiply(z)))}.
1461      * <p>
1462      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
1463      * input argument is {@code NaN}.
1464      * </p>
1465      * Infinite values in real or imaginary parts of the input may result in
1466      * infinite or NaN values returned in parts of the result.
1467      *
1468      * @return the square root of <code>1 - this<sup>2</sup></code>.
1469      */
1470     public FieldComplex<T> sqrt1z() {
1471         final FieldComplex<T> t2 = this.multiply(this);
1472         return createComplex(getPartsField().getOne().subtract(t2.real), t2.imaginary.negate()).sqrt();
1473     }
1474 
1475     /** {@inheritDoc}
1476      * <p>
1477      * This implementation compute the principal cube root by using a branch cut along real negative axis.
1478      * </p>
1479      */
1480     @Override
1481     public FieldComplex<T> cbrt() {
1482         final T              magnitude = FastMath.cbrt(abs().getRealPart());
1483         final FieldSinCos<T> sc        = FastMath.sinCos(getArgument().divide(3));
1484         return createComplex(magnitude.multiply(sc.cos()), magnitude.multiply(sc.sin()));
1485     }
1486 
1487     /** {@inheritDoc}
1488      * <p>
1489      * This implementation compute the principal n<sup>th</sup> root by using a branch cut along real negative axis.
1490      * </p>
1491      */
1492     @Override
1493     public FieldComplex<T> rootN(int n) {
1494         final T              magnitude = FastMath.pow(abs().getRealPart(), 1.0 / n);
1495         final FieldSinCos<T> sc        = FastMath.sinCos(getArgument().divide(n));
1496         return createComplex(magnitude.multiply(sc.cos()), magnitude.multiply(sc.sin()));
1497     }
1498 
1499     /**
1500      * Compute the
1501      * <a href="http://mathworld.wolfram.com/Tangent.html" TARGET="_top">
1502      * tangent</a> of this complex number.
1503      * Implements the formula:
1504      * <pre>
1505      *  <code>
1506      *   tan(a + bi) = sin(2a)/(cos(2a)+cosh(2b)) + [sinh(2b)/(cos(2a)+cosh(2b))]i
1507      *  </code>
1508      * </pre>
1509      * where the (real) functions on the right-hand side are
1510      * {@link FastMath#sin}, {@link FastMath#cos}, {@link FastMath#cosh} and
1511      * {@link FastMath#sinh}.
1512      * <p>
1513      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
1514      * input argument is {@code NaN}.
1515      * </p>
1516      * Infinite (or critical) values in real or imaginary parts of the input may
1517      * result in infinite or NaN values returned in parts of the result.
1518      * <pre>
1519      *  Examples:
1520      *  <code>
1521      *   tan(a &plusmn; INFINITY i) = 0 &plusmn; i
1522      *   tan(&plusmn;INFINITY + bi) = NaN + NaN i
1523      *   tan(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
1524      *   tan(&plusmn;&pi;/2 + 0 i) = &plusmn;INFINITY + NaN i
1525      *  </code>
1526      * </pre>
1527      *
1528      * @return the tangent of {@code this}.
1529      */
1530     @Override
1531     public FieldComplex<T> tan() {
1532         if (isNaN || real.isInfinite()) {
1533             return getNaN(getPartsField());
1534         }
1535         if (imaginary.getReal() > 20.0) {
1536             return getI(getPartsField());
1537         }
1538         if (imaginary.getReal() < -20.0) {
1539             return getMinusI(getPartsField());
1540         }
1541 
1542         final FieldSinCos<T> sc2r = FastMath.sinCos(real.multiply(2));
1543         T imaginary2 = imaginary.multiply(2);
1544         T d = sc2r.cos().add(FastMath.cosh(imaginary2));
1545 
1546         return createComplex(sc2r.sin().divide(d), FastMath.sinh(imaginary2).divide(d));
1547 
1548     }
1549 
1550     /**
1551      * Compute the
1552      * <a href="http://mathworld.wolfram.com/HyperbolicTangent.html" TARGET="_top">
1553      * hyperbolic tangent</a> of this complex number.
1554      * Implements the formula:
1555      * <pre>
1556      *  <code>
1557      *   tan(a + bi) = sinh(2a)/(cosh(2a)+cos(2b)) + [sin(2b)/(cosh(2a)+cos(2b))]i
1558      *  </code>
1559      * </pre>
1560      * where the (real) functions on the right-hand side are
1561      * {@link FastMath#sin}, {@link FastMath#cos}, {@link FastMath#cosh} and
1562      * {@link FastMath#sinh}.
1563      * <p>
1564      * Returns {@link #getNaN(Field)} if either real or imaginary part of the
1565      * input argument is {@code NaN}.
1566      * </p>
1567      * Infinite values in real or imaginary parts of the input may result in
1568      * infinite or NaN values returned in parts of the result.
1569      * <pre>
1570      *  Examples:
1571      *  <code>
1572      *   tanh(a &plusmn; INFINITY i) = NaN + NaN i
1573      *   tanh(&plusmn;INFINITY + bi) = &plusmn;1 + 0 i
1574      *   tanh(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
1575      *   tanh(0 + (&pi;/2)i) = NaN + INFINITY i
1576      *  </code>
1577      * </pre>
1578      *
1579      * @return the hyperbolic tangent of {@code this}.
1580      */
1581     @Override
1582     public FieldComplex<T> tanh() {
1583         if (isNaN || imaginary.isInfinite()) {
1584             return getNaN(getPartsField());
1585         }
1586         if (real.getReal() > 20.0) {
1587             return getOne(getPartsField());
1588         }
1589         if (real.getReal() < -20.0) {
1590             return getMinusOne(getPartsField());
1591         }
1592         T real2 = real.multiply(2);
1593         final FieldSinCos<T> sc2i = FastMath.sinCos(imaginary.multiply(2));
1594         T d = FastMath.cosh(real2).add(sc2i.cos());
1595 
1596         return createComplex(FastMath.sinh(real2).divide(d), sc2i.sin().divide(d));
1597     }
1598 
1599 
1600 
1601     /**
1602      * Compute the argument of this complex number.
1603      * The argument is the angle phi between the positive real axis and
1604      * the point representing this number in the complex plane.
1605      * The value returned is between -PI (not inclusive)
1606      * and PI (inclusive), with negative values returned for numbers with
1607      * negative imaginary parts.
1608      * <p>
1609      * If either real or imaginary part (or both) is NaN, NaN is returned.
1610      * Infinite parts are handled as {@code Math.atan2} handles them,
1611      * essentially treating finite parts as zero in the presence of an
1612      * infinite coordinate and returning a multiple of pi/4 depending on
1613      * the signs of the infinite parts.
1614      * See the javadoc for {@code Math.atan2} for full details.
1615      *
1616      * @return the argument of {@code this}.
1617      */
1618     public T getArgument() {
1619         return FastMath.atan2(getImaginaryPart(), getRealPart());
1620     }
1621 
1622     /**
1623      * Computes the n-th roots of this complex number.
1624      * The nth roots are defined by the formula:
1625      * <pre>
1626      *  <code>
1627      *   z<sub>k</sub> = abs<sup>1/n</sup> (cos(phi + 2&pi;k/n) + i (sin(phi + 2&pi;k/n))
1628      *  </code>
1629      * </pre>
1630      * for <i>{@code k=0, 1, ..., n-1}</i>, where {@code abs} and {@code phi}
1631      * are respectively the {@link #abs() modulus} and
1632      * {@link #getArgument() argument} of this complex number.
1633      * <p>
1634      * If one or both parts of this complex number is NaN, a list with just
1635      * one element, {@link #getNaN(Field)} is returned.
1636      * if neither part is NaN, but at least one part is infinite, the result
1637      * is a one-element list containing {@link #getInf(Field)}.
1638      *
1639      * @param n Degree of root.
1640      * @return a List of all {@code n}-th roots of {@code this}.
1641      * @throws MathIllegalArgumentException if {@code n <= 0}.
1642      */
1643     public List<FieldComplex<T>> nthRoot(int n) throws MathIllegalArgumentException {
1644 
1645         if (n <= 0) {
1646             throw new MathIllegalArgumentException(LocalizedCoreFormats.CANNOT_COMPUTE_NTH_ROOT_FOR_NEGATIVE_N,
1647                                                    n);
1648         }
1649 
1650         final List<FieldComplex<T>> result = new ArrayList<>();
1651 
1652         if (isNaN) {
1653             result.add(getNaN(getPartsField()));
1654             return result;
1655         }
1656         if (isInfinite()) {
1657             result.add(getInf(getPartsField()));
1658             return result;
1659         }
1660 
1661         // nth root of abs -- faster / more accurate to use a solver here?
1662         final T nthRootOfAbs = FastMath.pow(FastMath.hypot(real, imaginary), 1.0 / n);
1663 
1664         // Compute nth roots of complex number with k = 0, 1, ... n-1
1665         final T nthPhi = getArgument().divide(n);
1666         final double slice = 2 * FastMath.PI / n;
1667         T innerPart = nthPhi;
1668         for (int k = 0; k < n ; k++) {
1669             // inner part
1670             final FieldSinCos<T> scInner = FastMath.sinCos(innerPart);
1671             final T realPart = nthRootOfAbs.multiply(scInner.cos());
1672             final T imaginaryPart = nthRootOfAbs.multiply(scInner.sin());
1673             result.add(createComplex(realPart, imaginaryPart));
1674             innerPart = innerPart.add(slice);
1675         }
1676 
1677         return result;
1678     }
1679 
1680     /**
1681      * Create a complex number given the real and imaginary parts.
1682      *
1683      * @param realPart Real part.
1684      * @param imaginaryPart Imaginary part.
1685      * @return a new complex number instance.
1686      *
1687      * @see #valueOf(CalculusFieldElement, CalculusFieldElement)
1688      */
1689     protected FieldComplex<T> createComplex(final T realPart, final T imaginaryPart) {
1690         return new FieldComplex<>(realPart, imaginaryPart);
1691     }
1692 
1693     /**
1694      * Create a complex number given the real and imaginary parts.
1695      *
1696      * @param realPart Real part.
1697      * @param imaginaryPart Imaginary part.
1698      * @param <T> the type of the field elements
1699      * @return a Complex instance.
1700      */
1701     public static <T extends CalculusFieldElement<T>> FieldComplex<T>
1702         valueOf(T realPart, T imaginaryPart) {
1703         if (realPart.isNaN() || imaginaryPart.isNaN()) {
1704             return getNaN(realPart.getField());
1705         }
1706         return new FieldComplex<>(realPart, imaginaryPart);
1707     }
1708 
1709     /**
1710      * Create a complex number given only the real part.
1711      *
1712      * @param realPart Real part.
1713      * @param <T> the type of the field elements
1714      * @return a Complex instance.
1715      */
1716     public static <T extends CalculusFieldElement<T>> FieldComplex<T>
1717         valueOf(T realPart) {
1718         if (realPart.isNaN()) {
1719             return getNaN(realPart.getField());
1720         }
1721         return new FieldComplex<>(realPart);
1722     }
1723 
1724     /** {@inheritDoc} */
1725     @Override
1726     public FieldComplex<T> newInstance(double realPart) {
1727         return valueOf(getPartsField().getZero().newInstance(realPart));
1728     }
1729 
1730     /** {@inheritDoc} */
1731     @Override
1732     public FieldComplexField<T> getField() {
1733         return FieldComplexField.getField(getPartsField());
1734     }
1735 
1736     /** Get the {@link Field} the real and imaginary parts belong to.
1737      * @return {@link Field} the real and imaginary parts belong to
1738      */
1739     public Field<T> getPartsField() {
1740         return real.getField();
1741     }
1742 
1743     /** {@inheritDoc} */
1744     @Override
1745     public String toString() {
1746         return "(" + real + ", " + imaginary + ")";
1747     }
1748 
1749     /** {@inheritDoc} */
1750     @Override
1751     public FieldComplex<T> scalb(int n) {
1752         return createComplex(FastMath.scalb(real, n), FastMath.scalb(imaginary, n));
1753     }
1754 
1755     /** {@inheritDoc} */
1756     @Override
1757     public FieldComplex<T> ulp() {
1758         return createComplex(FastMath.ulp(real), FastMath.ulp(imaginary));
1759     }
1760 
1761     /** {@inheritDoc} */
1762     @Override
1763     public FieldComplex<T> hypot(FieldComplex<T> y) {
1764         if (isInfinite() || y.isInfinite()) {
1765             return getInf(getPartsField());
1766         } else if (isNaN() || y.isNaN()) {
1767             return getNaN(getPartsField());
1768         } else {
1769             return multiply(this).add(y.multiply(y)).sqrt();
1770         }
1771     }
1772 
1773     /** {@inheritDoc} */
1774     @Override
1775     public FieldComplex<T> linearCombination(final FieldComplex<T>[] a, final FieldComplex<T>[] b)
1776         throws MathIllegalArgumentException {
1777         final int n = 2 * a.length;
1778         final T[] realA      = MathArrays.buildArray(getPartsField(), n);
1779         final T[] realB      = MathArrays.buildArray(getPartsField(), n);
1780         final T[] imaginaryA = MathArrays.buildArray(getPartsField(), n);
1781         final T[] imaginaryB = MathArrays.buildArray(getPartsField(), n);
1782         for (int i = 0; i < a.length; ++i)  {
1783             final FieldComplex<T> ai = a[i];
1784             final FieldComplex<T> bi = b[i];
1785             realA[2 * i    ]      = ai.real;
1786             realA[2 * i + 1]      = ai.imaginary.negate();
1787             realB[2 * i    ]      = bi.real;
1788             realB[2 * i + 1]      = bi.imaginary;
1789             imaginaryA[2 * i    ] = ai.real;
1790             imaginaryA[2 * i + 1] = ai.imaginary;
1791             imaginaryB[2 * i    ] = bi.imaginary;
1792             imaginaryB[2 * i + 1] = bi.real;
1793         }
1794         return createComplex(real.linearCombination(realA,  realB),
1795                              real.linearCombination(imaginaryA, imaginaryB));
1796     }
1797 
1798     /** {@inheritDoc} */
1799     @Override
1800     public FieldComplex<T> linearCombination(final double[] a, final FieldComplex<T>[] b)
1801         throws MathIllegalArgumentException {
1802         final int n = a.length;
1803         final T[] realB      = MathArrays.buildArray(getPartsField(), n);
1804         final T[] imaginaryB = MathArrays.buildArray(getPartsField(), n);
1805         for (int i = 0; i < a.length; ++i)  {
1806             final FieldComplex<T> bi = b[i];
1807             realB[i]      = bi.real;
1808             imaginaryB[i] = bi.imaginary;
1809         }
1810         return createComplex(real.linearCombination(a,  realB),
1811                              real.linearCombination(a, imaginaryB));
1812     }
1813 
1814     /** {@inheritDoc} */
1815     @Override
1816     public FieldComplex<T> linearCombination(final FieldComplex<T> a1, final FieldComplex<T> b1, final FieldComplex<T> a2, final FieldComplex<T> b2) {
1817         return createComplex(real.linearCombination(a1.real, b1.real,
1818                                                     a1.imaginary.negate(), b1.imaginary,
1819                                                     a2.real, b2.real,
1820                                                     a2.imaginary.negate(), b2.imaginary),
1821                              real.linearCombination(a1.real, b1.imaginary,
1822                                                     a1.imaginary, b1.real,
1823                                                     a2.real, b2.imaginary,
1824                                                     a2.imaginary, b2.real));
1825     }
1826 
1827     /** {@inheritDoc} */
1828     @Override
1829     public FieldComplex<T> linearCombination(final double a1, final FieldComplex<T> b1, final double a2, final FieldComplex<T> b2) {
1830         return createComplex(real.linearCombination(a1, b1.real,
1831                                                     a2, b2.real),
1832                              real.linearCombination(a1, b1.imaginary,
1833                                                     a2, b2.imaginary));
1834     }
1835 
1836     /** {@inheritDoc} */
1837     @Override
1838     public FieldComplex<T> linearCombination(final FieldComplex<T> a1, final FieldComplex<T> b1,
1839                                                 final FieldComplex<T> a2, final FieldComplex<T> b2,
1840                                                 final FieldComplex<T> a3, final FieldComplex<T> b3) {
1841         FieldComplex<T>[] a = MathArrays.buildArray(getField(), 3);
1842         a[0] = a1;
1843         a[1] = a2;
1844         a[2] = a3;
1845         FieldComplex<T>[] b = MathArrays.buildArray(getField(), 3);
1846         b[0] = b1;
1847         b[1] = b2;
1848         b[2] = b3;
1849         return linearCombination(a, b);
1850     }
1851 
1852     /** {@inheritDoc} */
1853     @Override
1854     public FieldComplex<T> linearCombination(final double a1, final FieldComplex<T> b1,
1855                                                 final double a2, final FieldComplex<T> b2,
1856                                                 final double a3, final FieldComplex<T> b3) {
1857         FieldComplex<T>[] b = MathArrays.buildArray(getField(), 3);
1858         b[0] = b1;
1859         b[1] = b2;
1860         b[2] = b3;
1861         return linearCombination(new double[]  { a1, a2, a3 }, b);
1862     }
1863 
1864     /** {@inheritDoc} */
1865     @Override
1866     public FieldComplex<T> linearCombination(final FieldComplex<T> a1, final FieldComplex<T> b1,
1867                                                 final FieldComplex<T> a2, final FieldComplex<T> b2,
1868                                                 final FieldComplex<T> a3, final FieldComplex<T> b3,
1869                                                 final FieldComplex<T> a4, final FieldComplex<T> b4) {
1870         FieldComplex<T>[] a = MathArrays.buildArray(getField(), 4);
1871         a[0] = a1;
1872         a[1] = a2;
1873         a[2] = a3;
1874         a[3] = a4;
1875         FieldComplex<T>[] b = MathArrays.buildArray(getField(), 4);
1876         b[0] = b1;
1877         b[1] = b2;
1878         b[2] = b3;
1879         b[3] = b4;
1880         return linearCombination(a, b);
1881     }
1882 
1883     /** {@inheritDoc} */
1884     @Override
1885     public FieldComplex<T> linearCombination(final double a1, final FieldComplex<T> b1,
1886                                                 final double a2, final FieldComplex<T> b2,
1887                                                 final double a3, final FieldComplex<T> b3,
1888                                                 final double a4, final FieldComplex<T> b4) {
1889         FieldComplex<T>[] b = MathArrays.buildArray(getField(), 4);
1890         b[0] = b1;
1891         b[1] = b2;
1892         b[2] = b3;
1893         b[3] = b4;
1894         return linearCombination(new double[]  { a1, a2, a3, a4 }, b);
1895     }
1896 
1897     /** {@inheritDoc} */
1898     @Override
1899     public FieldComplex<T> ceil() {
1900         return createComplex(FastMath.ceil(getRealPart()), FastMath.ceil(getImaginaryPart()));
1901     }
1902 
1903     /** {@inheritDoc} */
1904     @Override
1905     public FieldComplex<T> floor() {
1906         return createComplex(FastMath.floor(getRealPart()), FastMath.floor(getImaginaryPart()));
1907     }
1908 
1909     /** {@inheritDoc} */
1910     @Override
1911     public FieldComplex<T> rint() {
1912         return createComplex(FastMath.rint(getRealPart()), FastMath.rint(getImaginaryPart()));
1913     }
1914 
1915     /** {@inheritDoc}
1916      * <p>
1917      * for complex numbers, the integer n corresponding to {@code this.subtract(remainder(a)).divide(a)}
1918      * is a <a href="https://en.wikipedia.org/wiki/Gaussian_integer">Wikipedia - Gaussian integer</a>.
1919      * </p>
1920      */
1921     @Override
1922     public FieldComplex<T> remainder(final double a) {
1923         return createComplex(FastMath.IEEEremainder(getRealPart(), a), FastMath.IEEEremainder(getImaginaryPart(), a));
1924     }
1925 
1926     /** {@inheritDoc}
1927      * <p>
1928      * for complex numbers, the integer n corresponding to {@code this.subtract(remainder(a)).divide(a)}
1929      * is a <a href="https://en.wikipedia.org/wiki/Gaussian_integer">Wikipedia - Gaussian integer</a>.
1930      * </p>
1931      */
1932     @Override
1933     public FieldComplex<T> remainder(final FieldComplex<T> a) {
1934         final FieldComplex<T> complexQuotient = divide(a);
1935         final T  qRInt           = FastMath.rint(complexQuotient.real);
1936         final T  qIInt           = FastMath.rint(complexQuotient.imaginary);
1937         return createComplex(real.subtract(qRInt.multiply(a.real)).add(qIInt.multiply(a.imaginary)),
1938                              imaginary.subtract(qRInt.multiply(a.imaginary)).subtract(qIInt.multiply(a.real)));
1939     }
1940 
1941     /** {@inheritDoc} */
1942     @Override
1943     public FieldComplex<T> sign() {
1944         if (isNaN() || isZero()) {
1945             return this;
1946         } else {
1947             return this.divide(FastMath.hypot(real, imaginary));
1948         }
1949     }
1950 
1951     /** {@inheritDoc}
1952      * <p>
1953      * The signs of real and imaginary parts are copied independently.
1954      * </p>
1955      */
1956     @Override
1957     public FieldComplex<T> copySign(final FieldComplex<T> z) {
1958         return createComplex(FastMath.copySign(getRealPart(), z.getRealPart()),
1959                              FastMath.copySign(getImaginaryPart(), z.getImaginaryPart()));
1960     }
1961 
1962     /** {@inheritDoc} */
1963     @Override
1964     public FieldComplex<T> copySign(double r) {
1965         return createComplex(FastMath.copySign(getRealPart(), r), FastMath.copySign(getImaginaryPart(), r));
1966     }
1967 
1968     /** {@inheritDoc} */
1969     @Override
1970     public FieldComplex<T> toDegrees() {
1971         return createComplex(FastMath.toDegrees(getRealPart()), FastMath.toDegrees(getImaginaryPart()));
1972     }
1973 
1974     /** {@inheritDoc} */
1975     @Override
1976     public FieldComplex<T> toRadians() {
1977         return createComplex(FastMath.toRadians(getRealPart()), FastMath.toRadians(getImaginaryPart()));
1978     }
1979 
1980     /** {@inheritDoc} */
1981     @Override
1982     public FieldComplex<T> getPi() {
1983         return getPi(getPartsField());
1984     }
1985 
1986 }