View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) 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 ASF 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    *      http://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  
18  package org.apache.commons.math.complex;
19  
20  import java.io.Serializable;
21  import org.apache.commons.math.util.MathUtils;
22  
23  /**
24   * Representation of a Complex number - a number which has both a 
25   * real and imaginary part.
26   * <p>
27   * Implementations of arithmetic operations handle <code>NaN</code> and
28   * infinite values according to the rules for {@link java.lang.Double}
29   * arithmetic, applying definitional formulas and returning <code>NaN</code> or
30   * infinite values in real or imaginary parts as these arise in computation. 
31   * See individual method javadocs for details.</p>
32   * <p>
33   * {@link #equals} identifies all values with <code>NaN</code> in either real 
34   * or imaginary part - e.g., <pre>
35   * <code>1 + NaNi  == NaN + i == NaN + NaNi.</code></pre></p>
36   *
37   * @version $Revision: 670469 $ $Date: 2008-06-23 10:01:38 +0200 (lun, 23 jun 2008) $
38   */
39  public class Complex implements Serializable  {
40  
41      /** Serializable version identifier */
42      private static final long serialVersionUID = -6530173849413811929L;
43      
44      /** The square root of -1. A number representing "0.0 + 1.0i" */    
45      public static final Complex I = new Complex(0.0, 1.0);
46      
47      /** A complex number representing "NaN + NaNi" */
48      public static final Complex NaN = new Complex(Double.NaN, Double.NaN);
49  
50      /** A complex number representing "+INF + INFi" */
51      public static final Complex INF = new Complex(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
52  
53      /** A complex number representing "1.0 + 0.0i" */    
54      public static final Complex ONE = new Complex(1.0, 0.0);
55      
56      /** A complex number representing "0.0 + 0.0i" */    
57      public static final Complex ZERO = new Complex(0.0, 0.0);
58      
59      /** 
60       * The imaginary part 
61       */
62      private final double imaginary;
63      
64      /** 
65       * The real part 
66       */
67      private final double real;
68      
69      /**
70       * Create a complex number given the real and imaginary parts.
71       *
72       * @param real the real part
73       * @param imaginary the imaginary part
74       */
75      public Complex(double real, double imaginary) {
76          super();
77          this.real = real;
78          this.imaginary = imaginary;
79      }
80  
81      /**
82       * Return the absolute value of this complex number.
83       * <p>
84       * Returns <code>NaN</code> if either real or imaginary part is
85       * <code>NaN</code> and <code>Double.POSITIVE_INFINITY</code> if
86       * neither part is <code>NaN</code>, but at least one part takes an infinite
87       * value.</p>
88       *
89       * @return the absolute value
90       */
91      public double abs() {
92          if (isNaN()) {
93              return Double.NaN;
94          }
95          
96          if (isInfinite()) {
97              return Double.POSITIVE_INFINITY;
98          }
99          
100         if (Math.abs(real) < Math.abs(imaginary)) {
101             if (imaginary == 0.0) {
102                 return Math.abs(real);
103             }
104             double q = real / imaginary;
105             return (Math.abs(imaginary) * Math.sqrt(1 + q*q));
106         } else {
107             if (real == 0.0) {
108                 return Math.abs(imaginary);
109             }
110             double q = imaginary / real;
111             return (Math.abs(real) * Math.sqrt(1 + q*q));
112         }
113     }
114     
115     /**
116      * Return the sum of this complex number and the given complex number.
117      * <p>
118      * Uses the definitional formula 
119      * <pre>
120      * (a + bi) + (c + di) = (a+c) + (b+d)i
121      * </pre></p>
122      * <p>
123      * If either this or <code>rhs</code> has a NaN value in either part,
124      * {@link #NaN} is returned; otherwise Inifinite and NaN values are
125      * returned in the parts of the result according to the rules for
126      * {@link java.lang.Double} arithmetic.</p> 
127      *
128      * @param rhs the other complex number
129      * @return the complex number sum
130      * @throws NullPointerException if <code>rhs</code> is null
131      */
132     public Complex add(Complex rhs) {   
133         return createComplex(real + rhs.getReal(),
134             imaginary + rhs.getImaginary());
135     }
136     
137     /**
138      * Return the conjugate of this complex number. The conjugate of
139      * "A + Bi" is "A - Bi". 
140      * <p>
141      * {@link #NaN} is returned if either the real or imaginary
142      * part of this Complex number equals <code>Double.NaN</code>.</p>
143      * <p>
144      * If the imaginary part is infinite, and the real part is not NaN, 
145      * the returned value has infinite imaginary part of the opposite
146      * sign - e.g. the conjugate of <code>1 + POSITIVE_INFINITY i</code>
147      * is <code>1 - NEGATIVE_INFINITY i</code></p>
148      *
149      * @return the conjugate of this Complex object
150      */
151     public Complex conjugate() {
152         if (isNaN()) {
153             return NaN;
154         }   
155         return createComplex(real, -imaginary);
156     }
157     
158     /**
159      * Return the quotient of this complex number and the given complex number.
160      * <p>
161      * Implements the definitional formula
162      * <pre><code>
163      *    a + bi          ac + bd + (bc - ad)i
164      *    ----------- = -------------------------
165      *    c + di               c<sup>2</sup> + d<sup>2</sup>
166      * </code></pre>
167      * but uses 
168      * <a href="http://doi.acm.org/10.1145/1039813.1039814">
169      * prescaling of operands</a> to limit the effects of overflows and
170      * underflows in the computation.</p>
171      * <p>
172      * Infinite and NaN values are handled / returned according to the
173      * following rules, applied in the order presented:
174      * <ul>
175      * <li>If either this or <code>rhs</code> has a NaN value in either part,
176      *  {@link #NaN} is returned.</li>
177      * <li>If <code>rhs</code> equals {@link #ZERO}, {@link #NaN} is returned.
178      * </li>
179      * <li>If this and <code>rhs</code> are both infinite,
180      * {@link #NaN} is returned.</li>
181      * <li>If this is finite (i.e., has no infinite or NaN parts) and
182      *  <code>rhs</code> is infinite (one or both parts infinite), 
183      * {@link #ZERO} is returned.</li>
184      * <li>If this is infinite and <code>rhs</code> is finite, NaN values are
185      * returned in the parts of the result if the {@link java.lang.Double}
186      * rules applied to the definitional formula force NaN results.</li>
187      * </ul></p>
188      * 
189      * @param rhs the other complex number
190      * @return the complex number quotient
191      * @throws NullPointerException if <code>rhs</code> is null
192      */
193     public Complex divide(Complex rhs) {
194         if (isNaN() || rhs.isNaN()) {
195             return NaN;
196         }
197 
198         double c = rhs.getReal();
199         double d = rhs.getImaginary();
200         if (c == 0.0 && d == 0.0) {
201             return NaN;
202         }
203         
204         if (rhs.isInfinite() && !isInfinite()) {
205             return ZERO;
206         }
207 
208         if (Math.abs(c) < Math.abs(d)) {
209             if (d == 0.0) {
210                 return createComplex(real/c, imaginary/c);
211             }
212             double q = c / d;
213             double denominator = c * q + d;
214             return createComplex((real * q + imaginary) / denominator,
215                 (imaginary * q - real) / denominator);
216         } else {
217             if (c == 0.0) {
218                 return createComplex(imaginary/d, -real/c);
219             }
220             double q = d / c;
221             double denominator = d * q + c;
222             return createComplex((imaginary * q + real) / denominator,
223                 (imaginary - real * q) / denominator);
224         }
225     }
226     
227     /**
228      * Test for the equality of two Complex objects.
229      * <p>
230      * If both the real and imaginary parts of two Complex numbers
231      * are exactly the same, and neither is <code>Double.NaN</code>, the two
232      * Complex objects are considered to be equal.</p>
233      * <p>
234      * All <code>NaN</code> values are considered to be equal - i.e, if either
235      * (or both) real and imaginary parts of the complex number are equal
236      * to <code>Double.NaN</code>, the complex number is equal to 
237      * <code>Complex.NaN</code>.</p>
238      *
239      * @param other Object to test for equality to this
240      * @return true if two Complex objects are equal, false if
241      *         object is null, not an instance of Complex, or
242      *         not equal to this Complex instance
243      * 
244      */
245     public boolean equals(Object other) {
246         boolean ret;
247         
248         if (this == other) { 
249             ret = true;
250         } else if (other == null) {
251             ret = false;
252         } else  {
253             try {
254                 Complex rhs = (Complex)other;
255                 if (rhs.isNaN()) {
256                     ret = this.isNaN();
257                 } else {
258                 ret = (Double.doubleToRawLongBits(real) ==
259                         Double.doubleToRawLongBits(rhs.getReal())) &&
260                     (Double.doubleToRawLongBits(imaginary) ==
261                         Double.doubleToRawLongBits(rhs.getImaginary())); 
262                 }
263             } catch (ClassCastException ex) {
264                 // ignore exception
265                 ret = false;
266             }
267         }
268       
269         return ret;
270     }
271     
272     /**
273      * Get a hashCode for the complex number.
274      * <p>
275      * All NaN values have the same hash code.</p>
276      * 
277      * @return a hash code value for this object
278      */
279     public int hashCode() {
280         if (isNaN()) {
281             return 7;
282         }
283         return 37 * (17 * MathUtils.hash(imaginary) + 
284             MathUtils.hash(real));
285     }
286 
287     /**
288      * Access the imaginary part.
289      *
290      * @return the imaginary part
291      */
292     public double getImaginary() {
293         return imaginary;
294     }
295 
296     /**
297      * Access the real part.
298      *
299      * @return the real part
300      */
301     public double getReal() {
302         return real;
303     }
304     
305     /**
306      * Returns true if either or both parts of this complex number is NaN;
307      * false otherwise
308      *
309      * @return  true if either or both parts of this complex number is NaN;
310      * false otherwise
311      */
312     public boolean isNaN() {
313         return Double.isNaN(real) || Double.isNaN(imaginary);        
314     }
315     
316     /**
317      * Returns true if either the real or imaginary part of this complex number
318      * takes an infinite value (either <code>Double.POSITIVE_INFINITY</code> or 
319      * <code>Double.NEGATIVE_INFINITY</code>) and neither part
320      * is <code>NaN</code>.
321      * 
322      * @return true if one or both parts of this complex number are infinite
323      * and neither part is <code>NaN</code>
324      */
325     public boolean isInfinite() {
326         return !isNaN() && 
327         (Double.isInfinite(real) || Double.isInfinite(imaginary));        
328     }
329     
330     /**
331      * Return the product of this complex number and the given complex number.
332      * <p>
333      * Implements preliminary checks for NaN and infinity followed by
334      * the definitional formula:
335      * <pre><code>
336      * (a + bi)(c + di) = (ac - bd) + (ad + bc)i
337      * </code></pre>
338      * </p>
339      * <p>
340      * Returns {@link #NaN} if either this or <code>rhs</code> has one or more
341      * NaN parts.
342      * </p>
343      * Returns {@link #INF} if neither this nor <code>rhs</code> has one or more
344      * NaN parts and if either this or <code>rhs</code> has one or more
345      * infinite parts (same result is returned regardless of the sign of the
346      * components).
347      * </p>
348      * <p>
349      * Returns finite values in components of the result per the
350      * definitional formula in all remaining cases.
351      *  </p>
352      * 
353      * @param rhs the other complex number
354      * @return the complex number product
355      * @throws NullPointerException if <code>rhs</code> is null
356      */
357     public Complex multiply(Complex rhs) {
358         if (isNaN() || rhs.isNaN()) {
359             return NaN;
360         }
361         if (Double.isInfinite(real) || Double.isInfinite(imaginary) ||
362             Double.isInfinite(rhs.real)|| Double.isInfinite(rhs.imaginary)) {
363             // we don't use Complex.isInfinite() to avoid testing for NaN again
364             return INF;
365         }
366         return createComplex(real * rhs.real - imaginary * rhs.imaginary,
367                 real * rhs.imaginary + imaginary * rhs.real);
368     }
369     
370     /**
371      * Return the additive inverse of this complex number.
372      * <p>
373      * Returns <code>Complex.NaN</code> if either real or imaginary
374      * part of this Complex number equals <code>Double.NaN</code>.</p>
375      *
376      * @return the negation of this complex number
377      */
378     public Complex negate() {
379         if (isNaN()) {
380             return NaN;
381         }
382         
383         return createComplex(-real, -imaginary);
384     }
385     
386     /**
387      * Return the difference between this complex number and the given complex
388      * number.
389       * <p>
390      * Uses the definitional formula 
391      * <pre>
392      * (a + bi) - (c + di) = (a-c) + (b-d)i
393      * </pre></p>
394      * <p>
395      * If either this or <code>rhs</code> has a NaN value in either part,
396      * {@link #NaN} is returned; otherwise inifinite and NaN values are
397      * returned in the parts of the result according to the rules for
398      * {@link java.lang.Double} arithmetic. </p>
399      * 
400      * @param rhs the other complex number
401      * @return the complex number difference
402      * @throws NullPointerException if <code>rhs</code> is null
403      */
404     public Complex subtract(Complex rhs) {
405         if (isNaN() || rhs.isNaN()) {
406             return NaN;
407         }
408         
409         return createComplex(real - rhs.getReal(),
410             imaginary - rhs.getImaginary());
411     }
412     
413     /**
414      * Compute the 
415      * <a href="http://mathworld.wolfram.com/InverseCosine.html" TARGET="_top">
416      * inverse cosine</a> of this complex number.
417      * <p>
418      * Implements the formula: <pre>
419      * <code> acos(z) = -i (log(z + i (sqrt(1 - z<sup>2</sup>))))</code></pre></p>
420      * <p>
421      * Returns {@link Complex#NaN} if either real or imaginary part of the 
422      * input argument is <code>NaN</code> or infinite.</p>
423      * 
424      * @return the inverse cosine of this complex number
425      * @since 1.2
426      */
427     public Complex acos() {
428         if (isNaN()) {
429             return Complex.NaN;
430         }
431 
432         return this.add(this.sqrt1z().multiply(Complex.I)).log()
433               .multiply(Complex.I.negate());
434     }
435     
436     /**
437      * Compute the 
438      * <a href="http://mathworld.wolfram.com/InverseSine.html" TARGET="_top">
439      * inverse sine</a> of this complex number.
440      * <p>
441      * Implements the formula: <pre>
442      * <code> asin(z) = -i (log(sqrt(1 - z<sup>2</sup>) + iz)) </code></pre></p>
443      * <p>
444      * Returns {@link Complex#NaN} if either real or imaginary part of the 
445      * input argument is <code>NaN</code> or infinite.</p>
446      * 
447      * @return the inverse sine of this complex number.
448      * @since 1.2
449      */
450     public Complex asin() {
451         if (isNaN()) {
452             return Complex.NaN;
453         }
454 
455         return sqrt1z().add(this.multiply(Complex.I)).log()
456               .multiply(Complex.I.negate());
457     }
458     
459     /**
460      * Compute the 
461      * <a href="http://mathworld.wolfram.com/InverseTangent.html" TARGET="_top">
462      * inverse tangent</a> of this complex number.
463      * <p>
464      * Implements the formula: <pre>
465      * <code> atan(z) = (i/2) log((i + z)/(i - z)) </code></pre></p>
466      * <p>
467      * Returns {@link Complex#NaN} if either real or imaginary part of the 
468      * input argument is <code>NaN</code> or infinite.</p>
469      * 
470      * @return the inverse tangent of this complex number
471      * @since 1.2
472      */
473     public Complex atan() {
474         if (isNaN()) {
475             return Complex.NaN;
476         }
477         
478         return this.add(Complex.I).divide(Complex.I.subtract(this)).log()
479             .multiply(Complex.I.divide(createComplex(2.0, 0.0)));
480     }
481     
482     /**
483      * Compute the 
484      * <a href="http://mathworld.wolfram.com/Cosine.html" TARGET="_top">
485      * cosine</a>
486      * of this complex number.
487      * <p>
488      * Implements the formula: <pre>
489      * <code> cos(a + bi) = cos(a)cosh(b) - sin(a)sinh(b)i</code></pre>
490      * where the (real) functions on the right-hand side are
491      * {@link java.lang.Math#sin}, {@link java.lang.Math#cos}, 
492      * {@link MathUtils#cosh} and {@link MathUtils#sinh}.</p>
493      * <p>
494      * Returns {@link Complex#NaN} if either real or imaginary part of the 
495      * input argument is <code>NaN</code>.</p>
496      * <p>
497      * Infinite values in real or imaginary parts of the input may result in
498      * infinite or NaN values returned in parts of the result.<pre>
499      * Examples: 
500      * <code>
501      * cos(1 &plusmn; INFINITY i) = 1 &#x2213; INFINITY i
502      * cos(&plusmn;INFINITY + i) = NaN + NaN i
503      * cos(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i</code></pre></p>
504      * 
505      * @return the cosine of this complex number
506      * @since 1.2
507      */
508     public Complex cos() {
509         if (isNaN()) {
510             return Complex.NaN;
511         }
512         
513         return createComplex(Math.cos(real) * MathUtils.cosh(imaginary),
514             -Math.sin(real) * MathUtils.sinh(imaginary));
515     }
516     
517     /**
518      * Compute the 
519      * <a href="http://mathworld.wolfram.com/HyperbolicCosine.html" TARGET="_top">
520      * hyperbolic cosine</a> of this complex number.
521      * <p>
522      * Implements the formula: <pre>
523      * <code> cosh(a + bi) = cosh(a)cos(b) + sinh(a)sin(b)i</code></pre>
524      * where the (real) functions on the right-hand side are
525      * {@link java.lang.Math#sin}, {@link java.lang.Math#cos}, 
526      * {@link MathUtils#cosh} and {@link MathUtils#sinh}.</p>
527      * <p>
528      * Returns {@link Complex#NaN} if either real or imaginary part of the 
529      * input argument is <code>NaN</code>.</p>
530      * <p>
531      * Infinite values in real or imaginary parts of the input may result in
532      * infinite or NaN values returned in parts of the result.<pre>
533      * Examples: 
534      * <code>
535      * cosh(1 &plusmn; INFINITY i) = NaN + NaN i
536      * cosh(&plusmn;INFINITY + i) = INFINITY &plusmn; INFINITY i
537      * cosh(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i</code></pre></p>
538      * 
539      * @return the hyperbolic cosine of this complex number.
540      * @since 1.2
541      */
542     public Complex cosh() {
543         if (isNaN()) {
544             return Complex.NaN;
545         }
546         
547         return createComplex(MathUtils.cosh(real) * Math.cos(imaginary),
548             MathUtils.sinh(real) * Math.sin(imaginary));
549     }
550     
551     /**
552      * Compute the
553      * <a href="http://mathworld.wolfram.com/ExponentialFunction.html" TARGET="_top">
554      * exponential function</a> of this complex number.
555      * <p>
556      * Implements the formula: <pre>
557      * <code> exp(a + bi) = exp(a)cos(b) + exp(a)sin(b)i</code></pre>
558      * where the (real) functions on the right-hand side are
559      * {@link java.lang.Math#exp}, {@link java.lang.Math#cos}, and
560      * {@link java.lang.Math#sin}.</p>
561      * <p>
562      * Returns {@link Complex#NaN} if either real or imaginary part of the 
563      * input argument is <code>NaN</code>.</p>
564      * <p>
565      * Infinite values in real or imaginary parts of the input may result in
566      * infinite or NaN values returned in parts of the result.<pre>
567      * Examples: 
568      * <code>
569      * exp(1 &plusmn; INFINITY i) = NaN + NaN i
570      * exp(INFINITY + i) = INFINITY + INFINITY i
571      * exp(-INFINITY + i) = 0 + 0i
572      * exp(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i</code></pre></p>
573      * 
574      * @return <i>e</i><sup><code>this</code></sup>
575      * @since 1.2
576      */
577     public Complex exp() {
578         if (isNaN()) {
579             return Complex.NaN;
580         }
581         
582         double expReal = Math.exp(real);
583         return createComplex(expReal *  Math.cos(imaginary), expReal * Math.sin(imaginary));
584     }
585     
586     /**
587      * Compute the 
588      * <a href="http://mathworld.wolfram.com/NaturalLogarithm.html" TARGET="_top">
589      * natural logarithm</a> of this complex number.
590      * <p>
591      * Implements the formula: <pre>
592      * <code> log(a + bi) = ln(|a + bi|) + arg(a + bi)i</code></pre>
593      * where ln on the right hand side is {@link java.lang.Math#log},
594      * <code>|a + bi|</code> is the modulus, {@link Complex#abs},  and
595      * <code>arg(a + bi) = {@link java.lang.Math#atan2}(b, a)</code></p>
596      * <p>
597      * Returns {@link Complex#NaN} if either real or imaginary part of the 
598      * input argument is <code>NaN</code>.</p>
599      * <p>
600      * Infinite (or critical) values in real or imaginary parts of the input may
601      * result in infinite or NaN values returned in parts of the result.<pre>
602      * Examples: 
603      * <code>
604      * log(1 &plusmn; INFINITY i) = INFINITY &plusmn; (&pi;/2)i
605      * log(INFINITY + i) = INFINITY + 0i
606      * log(-INFINITY + i) = INFINITY + &pi;i
607      * log(INFINITY &plusmn; INFINITY i) = INFINITY &plusmn; (&pi;/4)i
608      * log(-INFINITY &plusmn; INFINITY i) = INFINITY &plusmn; (3&pi;/4)i
609      * log(0 + 0i) = -INFINITY + 0i
610      * </code></pre></p>
611      * 
612      * @return ln of this complex number.
613      * @since 1.2
614      */
615     public Complex log() {
616         if (isNaN()) {
617             return Complex.NaN;
618         }
619 
620         return createComplex(Math.log(abs()),
621             Math.atan2(imaginary, real));        
622     }
623     
624     /**
625      * Returns of value of this complex number raised to the power of <code>x</code>.
626      * <p>
627      * Implements the formula: <pre>
628      * <code> y<sup>x</sup> = exp(x&middot;log(y))</code></pre> 
629      * where <code>exp</code> and <code>log</code> are {@link #exp} and
630      * {@link #log}, respectively.</p>
631      * <p>
632      * Returns {@link Complex#NaN} if either real or imaginary part of the 
633      * input argument is <code>NaN</code> or infinite, or if <code>y</code>
634      * equals {@link Complex#ZERO}.</p>
635      * 
636      * @param x the exponent.
637      * @return <code>this</code><sup><code>x</code></sup>
638      * @throws NullPointerException if x is null
639      * @since 1.2
640      */
641     public Complex pow(Complex x) {
642         if (x == null) {
643             throw new NullPointerException();
644         }
645         return this.log().multiply(x).exp();
646     }
647     
648     /**
649      * Compute the 
650      * <a href="http://mathworld.wolfram.com/Sine.html" TARGET="_top">
651      * sine</a>
652      * of this complex number.
653      * <p>
654      * Implements the formula: <pre>
655      * <code> sin(a + bi) = sin(a)cosh(b) - cos(a)sinh(b)i</code></pre>
656      * where the (real) functions on the right-hand side are
657      * {@link java.lang.Math#sin}, {@link java.lang.Math#cos}, 
658      * {@link MathUtils#cosh} and {@link MathUtils#sinh}.</p>
659      * <p>
660      * Returns {@link Complex#NaN} if either real or imaginary part of the 
661      * input argument is <code>NaN</code>.</p>
662      * <p>
663      * Infinite values in real or imaginary parts of the input may result in
664      * infinite or NaN values returned in parts of the result.<pre>
665      * Examples: 
666      * <code>
667      * sin(1 &plusmn; INFINITY i) = 1 &plusmn; INFINITY i
668      * sin(&plusmn;INFINITY + i) = NaN + NaN i
669      * sin(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i</code></pre></p>
670      * 
671      * @return the sine of this complex number.
672      * @since 1.2
673      */
674     public Complex sin() {
675         if (isNaN()) {
676             return Complex.NaN;
677         }
678         
679         return createComplex(Math.sin(real) * MathUtils.cosh(imaginary),
680             Math.cos(real) * MathUtils.sinh(imaginary));
681     }
682     
683     /**
684      * Compute the 
685      * <a href="http://mathworld.wolfram.com/HyperbolicSine.html" TARGET="_top">
686      * hyperbolic sine</a> of this complex number.
687      * <p>
688      * Implements the formula: <pre>
689      * <code> sinh(a + bi) = sinh(a)cos(b)) + cosh(a)sin(b)i</code></pre>
690      * where the (real) functions on the right-hand side are
691      * {@link java.lang.Math#sin}, {@link java.lang.Math#cos}, 
692      * {@link MathUtils#cosh} and {@link MathUtils#sinh}.</p>
693      * <p>
694      * Returns {@link Complex#NaN} if either real or imaginary part of the 
695      * input argument is <code>NaN</code>.</p>
696      * <p>
697      * Infinite values in real or imaginary parts of the input may result in
698      * infinite or NaN values returned in parts of the result.<pre>
699      * Examples: 
700      * <code>
701      * sinh(1 &plusmn; INFINITY i) = NaN + NaN i
702      * sinh(&plusmn;INFINITY + i) = &plusmn; INFINITY + INFINITY i
703      * sinh(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i</code></pre></p>
704      * 
705      * @return the hyperbolic sine of this complex number
706      * @since 1.2
707      */
708     public Complex sinh() {
709         if (isNaN()) {
710             return Complex.NaN;
711         }
712         
713         return createComplex(MathUtils.sinh(real) * Math.cos(imaginary),
714             MathUtils.cosh(real) * Math.sin(imaginary));
715     }
716     
717     /**
718      * Compute the 
719      * <a href="http://mathworld.wolfram.com/SquareRoot.html" TARGET="_top">
720      * square root</a> of this complex number.
721      * <p>
722      * Implements the following algorithm to compute <code>sqrt(a + bi)</code>: 
723      * <ol><li>Let <code>t = sqrt((|a| + |a + bi|) / 2)</code></li>
724      * <li><pre>if <code> a &#8805; 0</code> return <code>t + (b/2t)i</code>
725      *  else return <code>|b|/2t + sign(b)t i </code></pre></li>
726      * </ol>
727      * where <ul>
728      * <li><code>|a| = {@link Math#abs}(a)</code></li>
729      * <li><code>|a + bi| = {@link Complex#abs}(a + bi) </code></li>
730      * <li><code>sign(b) =  {@link MathUtils#indicator}(b) </code>
731      * </ul></p>
732      * <p>
733      * Returns {@link Complex#NaN} if either real or imaginary part of the 
734      * input argument is <code>NaN</code>.</p>
735      * <p>
736      * Infinite values in real or imaginary parts of the input may result in
737      * infinite or NaN values returned in parts of the result.<pre>
738      * Examples: 
739      * <code>
740      * sqrt(1 &plusmn; INFINITY i) = INFINITY + NaN i
741      * sqrt(INFINITY + i) = INFINITY + 0i
742      * sqrt(-INFINITY + i) = 0 + INFINITY i
743      * sqrt(INFINITY &plusmn; INFINITY i) = INFINITY + NaN i
744      * sqrt(-INFINITY &plusmn; INFINITY i) = NaN &plusmn; INFINITY i
745      * </code></pre></p>
746      * 
747      * @return the square root of this complex number
748      * @since 1.2
749      */
750     public Complex sqrt() {
751         if (isNaN()) {
752             return Complex.NaN;
753         }
754         
755         if (real == 0.0 && imaginary == 0.0) {
756             return createComplex(0.0, 0.0);
757         }
758         
759         double t = Math.sqrt((Math.abs(real) + abs()) / 2.0);
760         if (real >= 0.0) {
761             return createComplex(t, imaginary / (2.0 * t));
762         } else {
763             return createComplex(Math.abs(imaginary) / (2.0 * t),
764                 MathUtils.indicator(imaginary) * t);
765         }
766     }
767     
768     /**
769      * Compute the 
770      * <a href="http://mathworld.wolfram.com/SquareRoot.html" TARGET="_top">
771      * square root</a> of 1 - <code>this</code><sup>2</sup> for this complex
772      * number.
773      * <p>
774      * Computes the result directly as 
775      * <code>sqrt(Complex.ONE.subtract(z.multiply(z)))</code>.</p>
776      * <p>
777      * Returns {@link Complex#NaN} if either real or imaginary part of the 
778      * input argument is <code>NaN</code>.</p>
779      * <p>
780      * Infinite values in real or imaginary parts of the input may result in
781      * infinite or NaN values returned in parts of the result.</p>
782      * 
783      * @return the square root of 1 - <code>this</code><sup>2</sup>
784      * @since 1.2
785      */
786     public Complex sqrt1z() {
787         return createComplex(1.0, 0.0).subtract(this.multiply(this)).sqrt();
788     }
789     
790     /**
791      * Compute the 
792      * <a href="http://mathworld.wolfram.com/Tangent.html" TARGET="_top">
793      * tangent</a> of this complex number.
794      * <p>
795      * Implements the formula: <pre>
796      * <code>tan(a + bi) = sin(2a)/(cos(2a)+cosh(2b)) + [sinh(2b)/(cos(2a)+cosh(2b))]i</code></pre>
797      * where the (real) functions on the right-hand side are
798      * {@link java.lang.Math#sin}, {@link java.lang.Math#cos}, 
799      * {@link MathUtils#cosh} and {@link MathUtils#sinh}.</p>
800      * <p>
801      * Returns {@link Complex#NaN} if either real or imaginary part of the 
802      * input argument is <code>NaN</code>.</p>
803      * <p>
804      * Infinite (or critical) values in real or imaginary parts of the input may
805      * result in infinite or NaN values returned in parts of the result.<pre>
806      * Examples: 
807      * <code>
808      * tan(1 &plusmn; INFINITY i) = 0 + NaN i
809      * tan(&plusmn;INFINITY + i) = NaN + NaN i
810      * tan(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
811      * tan(&plusmn;&pi;/2 + 0 i) = &plusmn;INFINITY + NaN i</code></pre></p>
812      * 
813      * @return the tangent of this complex number
814      * @since 1.2
815      */
816     public Complex tan() {
817         if (isNaN()) {
818             return Complex.NaN;
819         }
820         
821         double real2 = 2.0 * real;
822         double imaginary2 = 2.0 * imaginary;
823         double d = Math.cos(real2) + MathUtils.cosh(imaginary2);
824         
825         return createComplex(Math.sin(real2) / d, MathUtils.sinh(imaginary2) / d);
826     }
827     
828     /**
829      * Compute the
830      * <a href="http://mathworld.wolfram.com/HyperbolicTangent.html" TARGET="_top">
831      * hyperbolic tangent</a> of this complex number.
832      * <p>
833      * Implements the formula: <pre>
834      * <code>tan(a + bi) = sinh(2a)/(cosh(2a)+cos(2b)) + [sin(2b)/(cosh(2a)+cos(2b))]i</code></pre>
835      * where the (real) functions on the right-hand side are
836      * {@link java.lang.Math#sin}, {@link java.lang.Math#cos}, 
837      * {@link MathUtils#cosh} and {@link MathUtils#sinh}.</p>
838      * <p>
839      * Returns {@link Complex#NaN} if either real or imaginary part of the 
840      * input argument is <code>NaN</code>.</p>
841      * <p>
842      * Infinite values in real or imaginary parts of the input may result in
843      * infinite or NaN values returned in parts of the result.<pre>
844      * Examples: 
845      * <code>
846      * tanh(1 &plusmn; INFINITY i) = NaN + NaN i
847      * tanh(&plusmn;INFINITY + i) = NaN + 0 i
848      * tanh(&plusmn;INFINITY &plusmn; INFINITY i) = NaN + NaN i
849      * tanh(0 + (&pi;/2)i) = NaN + INFINITY i</code></pre></p>
850      *
851      * @return the hyperbolic tangent of this complex number
852      * @since 1.2
853      */
854     public Complex tanh() {
855         if (isNaN()) {
856             return Complex.NaN;
857         }
858         
859         double real2 = 2.0 * real;
860         double imaginary2 = 2.0 * imaginary;
861         double d = MathUtils.cosh(real2) + Math.cos(imaginary2);
862         
863         return createComplex(MathUtils.sinh(real2) / d, Math.sin(imaginary2) / d);
864     }
865 
866     /**
867      * Create a complex number given the real and imaginary parts.
868      *
869      * @param real the real part
870      * @param imaginary the imaginary part
871      * @return a new complex number instance
872      * @since 1.2
873      */
874     protected Complex createComplex(double real, double imaginary) {
875         return new Complex(real, imaginary);
876     }
877 }