View Javadoc

    1   /*
    2    * Copyright 2003-2005 The Apache Software Foundation.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16
    17  package org.apache.commons.math.complex;
    18
    19  import java.io.Serializable;
    20  import org.apache.commons.math.util.MathUtils;
    21
    22  /***
    23   * Representation of a Complex number - a number which has both a
    24   * real and imaginary part.
    25   * <p>
    26   * Implementations of arithmetic operations handle <code>NaN</code> and
    27   * infinite values according to the rules for {@link java.lang.Double}
    28   * arithmetic, applying definitional formulas and returning <code>NaN</code> or
    29   * infinite values in real or imaginary parts as these arise in computation.
    30   * See individual method javadocs for details.
    31   * <p>
    32   * {@link #equals} identifies all values with <code>NaN</code> in either real
    33   * or imaginary part - e.g., <pre>
    34   * <code>1 + NaNi  == NaN + i == NaN + NaNi.</code></pre>
    35   *
    36   * @author Apache Software Foundation
    37   * @version $Revision: 349309 $ $Date: 2005-11-27 13:55:08 -0700 (Sun, 27 Nov 2005) $
    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 "1.0 + 0.0i" */
    51      public static final Complex ONE = new Complex(1.0, 0.0);
    52
    53      /*** A complex number representing "0.0 + 0.0i" */
    54      public static final Complex ZERO = new Complex(0.0, 0.0);
    55
    56      /*** The imaginary part */
    57      protected double imaginary;
    58
    59      /*** The real part */
    60      protected double real;
    61
    62      /***
    63       * Create a complex number given the real and imaginary parts.
    64       *
    65       * @param real the real part
    66       * @param imaginary the imaginary part
    67       */
    68      public Complex(double real, double imaginary) {
    69          super();
    70          this.real = real;
    71          this.imaginary = imaginary;
    72      }
    73
    74      /***
    75       * Return the absolute value of this complex number.
    76       * <p>
    77       * Returns <code>NaN</code> if either real or imaginary part is
    78       * <code>NaN</code> and <code>Double.POSITIVE_INFINITY</code> if
    79       * neither part is <code>NaN</code>, but at least one part takes an infinite
    80       * value.
    81       *
    82       * @return the absolute value
    83       */
    84      public double abs() {
    85          if (isNaN()) {
    86              return Double.NaN;
    87          }
    88
    89          if (isInfinite()) {
    90              return Double.POSITIVE_INFINITY;
    91          }
    92
    93          if (Math.abs(real) < Math.abs(imaginary)) {
    94              if (imaginary == 0.0) {
    95                  return Math.abs(real);
    96              }
    97              double q = real / imaginary;
    98              return (Math.abs(imaginary) * Math.sqrt(1 + q*q));
    99          } else {
    100             if (real == 0.0) {
    101                 return Math.abs(imaginary);
    102             }
    103             double q = imaginary / real;
    104             return (Math.abs(real) * Math.sqrt(1 + q*q));
    105         }
    106     }
    107
    108     /***
    109      * Return the sum of this complex number and the given complex number.
    110      * <p>
    111      * Uses the definitional formula
    112      * <pre>
    113      * (a + bi) + (c + di) = (a+c) + (b+d)i
    114      * </pre>
    115      * <p>
    116      * If either this or <code>rhs</code> has a NaN value in either part,
    117      * {@link #NaN} is returned; otherwise Inifinite and NaN values are
    118      * returned in the parts of the result according to the rules for
    119      * {@link java.lang.Double} arithmetic.
    120      *
    121      * @param rhs the other complex number
    122      * @return the complex number sum
    123      * @throws NullPointerException if <code>rhs</code> is null
    124      */
    125     public Complex add(Complex rhs) {
    126         return new Complex(real + rhs.getReal(),
    127             imaginary + rhs.getImaginary());
    128     }
    129
    130     /***
    131      * Return the conjugate of this complex number. The conjugate of
    132      * "A + Bi" is "A - Bi".
    133      * <p>
    134      * {@link #NaN} is returned if either the real or imaginary
    135      * part of this Complex number equals <code>Double.NaN</code>.
    136      * <p>
    137      * If the imaginary part is infinite, and the real part is not NaN,
    138      * the returned value has infinite imaginary part of the opposite
    139      * sign - e.g. the conjugate of <code>1 + POSITIVE_INFINITY i</code>
    140      * is <code>1 - NEGATIVE_INFINITY i</code>
    141      *
    142      * @return the conjugate of this Complex object
    143      */
    144     public Complex conjugate() {
    145         if (isNaN()) {
    146             return NaN;
    147         }
    148         return new Complex(real, -imaginary);
    149     }
    150
    151     /***
    152      * Return the quotient of this complex number and the given complex number.
    153      * <p>
    154      * Implements the definitional formula
    155      * <pre><code>
    156      *    a + bi          ac + bd + (bc - ad)i
    157      *    ----------- = -------------------------
    158      *    c + di               c<sup>2</sup> + d<sup>2</sup>
    159      * </code></pre>
    160      * but uses
    161      * <a href="http://doi.acm.org/10.1145/1039813.1039814">
    162      * prescaling of operands</a> to limit the effects of overflows and
    163      * underflows in the computation.
    164      * <p>
    165      * Infinite and NaN values are handled / returned according to the
    166      * following rules, applied in the order presented:
    167      * <ul>
    168      * <li>If either this or <code>rhs</code> has a NaN value in either part,
    169      *  {@link #NaN} is returned.</li>
    170      * <li>If <code>rhs</code> equals {@link #ZERO}, {@link #NaN} is returned.
    171      * </li>
    172      * <li>If this and <code>rhs</code> are both infinite,
    173      * {@link #NaN} is returned.</li>
    174      * <li>If this is finite (i.e., has no infinite or NaN parts) and
    175      *  <code>rhs</code> is infinite (one or both parts infinite),
    176      * {@link #ZERO} is returned.</li>
    177      * <li>If this is infinite and <code>rhs</code> is finite, NaN values are
    178      * returned in the parts of the result if the {@link java.lang.Double}
    179      * rules applied to the definitional formula force NaN results.</li>
    180      * </ul>
    181      *
    182      * @param rhs the other complex number
    183      * @return the complex number quotient
    184      * @throws NullPointerException if <code>rhs</code> is null
    185      */
    186     public Complex divide(Complex rhs) {
    187         if (isNaN() || rhs.isNaN()) {
    188             return NaN;
    189         }
    190
    191         double c = rhs.getReal();
    192         double d = rhs.getImaginary();
    193         if (c == 0.0 && d == 0.0) {
    194             return NaN;
    195         }
    196
    197         if (rhs.isInfinite() && !isInfinite()) {
    198             return ZERO;
    199         }
    200
    201         if (Math.abs(c) < Math.abs(d)) {
    202             if (d == 0.0) {
    203                 return new Complex(real/c, imaginary/c);
    204             }
    205             double q = c / d;
    206             double denominator = c * q + d;
    207             return new Complex((real * q + imaginary) / denominator,
    208                 (imaginary * q - real) / denominator);
    209         } else {
    210             if (c == 0.0) {
    211                 return new Complex(imaginary/d, -real/c);
    212             }
    213             double q = d / c;
    214             double denominator = d * q + c;
    215             return new Complex((imaginary * q + real) / denominator,
    216                 (imaginary - real * q) / denominator);
    217         }
    218     }
    219
    220     /***
    221      * Test for the equality of two Complex objects.
    222      * <p>
    223      * If both the real and imaginary parts of two Complex numbers
    224      * are exactly the same, and neither is <code>Double.NaN</code>, the two
    225      * Complex objects are considered to be equal.
    226      * <p>
    227      * All <code>NaN</code> values are considered to be equal - i.e, if either
    228      * (or both) real and imaginary parts of the complex number are equal
    229      * to <code>Double.NaN</code>, the complex number is equal to
    230      * <code>Complex.NaN</code>.
    231      *
    232      * @param other Object to test for equality to this
    233      * @return true if two Complex objects are equal, false if
    234      *         object is null, not an instance of Complex, or
    235      *         not equal to this Complex instance
    236      *
    237      */
    238     public boolean equals(Object other) {
    239         boolean ret;
    240
    241         if (this == other) {
    242             ret = true;
    243         } else if (other == null) {
    244             ret = false;
    245         } else  {
    246             try {
    247                 Complex rhs = (Complex)other;
    248                 if (rhs.isNaN()) {
    249                     ret = this.isNaN();
    250                 } else {
    251                 ret = (Double.doubleToRawLongBits(real) ==
    252                         Double.doubleToRawLongBits(rhs.getReal())) &&
    253                     (Double.doubleToRawLongBits(imaginary) ==
    254                         Double.doubleToRawLongBits(rhs.getImaginary()));
    255                 }
    256             } catch (ClassCastException ex) {
    257                 // ignore exception
    258                 ret = false;
    259             }
    260         }
    261
    262         return ret;
    263     }
    264
    265     /***
    266      * Get a hashCode for the complex number.
    267      * <p>
    268      * All NaN values have the same hash code.
    269      *
    270      * @return a hash code value for this object
    271      */
    272     public int hashCode() {
    273         if (isNaN()) {
    274             return 7;
    275         }
    276         return 37 * (17 * MathUtils.hash(imaginary) +
    277             MathUtils.hash(real));
    278     }
    279
    280     /***
    281      * Access the imaginary part.
    282      *
    283      * @return the imaginary part
    284      */
    285     public double getImaginary() {
    286         return imaginary;
    287     }
    288
    289     /***
    290      * Access the real part.
    291      *
    292      * @return the real part
    293      */
    294     public double getReal() {
    295         return real;
    296     }
    297
    298     /***
    299      * Returns true if either or both parts of this complex number is NaN;
    300      * false otherwise
    301      *
    302      * @return  true if either or both parts of this complex number is NaN;
    303      * false otherwise
    304      */
    305     public boolean isNaN() {
    306         return Double.isNaN(real) || Double.isNaN(imaginary);
    307     }
    308
    309     /***
    310      * Returns true if either the real or imaginary part of this complex number
    311      * takes an infinite value (either <code>Double.POSITIVE_INFINITY</code> or
    312      * <code>Double.NEGATIVE_INFINITY</code>) and neither part
    313      * is <code>NaN</code>.
    314      *
    315      * @return true if one or both parts of this complex number are infinite
    316      * and neither part is <code>NaN</code>
    317      */
    318     public boolean isInfinite() {
    319         return !isNaN() &&
    320         (Double.isInfinite(real) || Double.isInfinite(imaginary));
    321     }
    322
    323     /***
    324      * Return the product of this complex number and the given complex number.
    325      * <p>
    326      * Implements the definitional formula:
    327      * <pre><code>
    328      * (a + bi)(c + di) = (ac - bd) + (ad + bc)i
    329      * </code></pre>
    330      * <p>
    331      * Returns {@link #NaN} if either this or <code>rhs</code> has one or more
    332      * NaN parts.
    333      * <p>
    334      * Returns NaN or infinite values in components of the result per the
    335      * definitional formula and and the rules for {@link java.lang.Double}
    336      * arithmetic.  Examples:
    337      * <pre><code>
    338      *  (1 + i) (INF + i)  =  INF + INFi
    339      *  (1 + INFi) (1 - INFi) = INF + NaNi
    340      *  (-INF + -INFi)(1 + NaNi) = NaN + NaNi
    341      *  </code></pre>
    342      *
    343      * @param rhs the other complex number
    344      * @return the complex number product
    345      * @throws NullPointerException if <code>rhs</code> is null
    346      */
    347     public Complex multiply(Complex rhs) {
    348         if (isNaN() || rhs.isNaN()) {
    349             return NaN;
    350         }
    351         return new Complex(real * rhs.real - imaginary * rhs.imaginary,
    352                 real * rhs.imaginary + imaginary * rhs.real);
    353     }
    354
    355     /***
    356      * Return the additive inverse of this complex number.
    357      * <p>
    358      * Returns <code>Complex.NaN</code> if either real or imaginary
    359      * part of this Complex number equals <code>Double.NaN</code>.
    360      *
    361      * @return the negation of this complex number
    362      */
    363     public Complex negate() {
    364         if (isNaN()) {
    365             return NaN;
    366         }
    367
    368         return new Complex(-real, -imaginary);
    369     }
    370
    371     /***
    372      * Return the difference between this complex number and the given complex
    373      * number.
    374       * <p>
    375      * Uses the definitional formula
    376      * <pre>
    377      * (a + bi) - (c + di) = (a-c) + (b-d)i
    378      * </pre>
    379      * <p>
    380      * If either this or <code>rhs</code> has a NaN value in either part,
    381      * {@link #NaN} is returned; otherwise inifinite and NaN values are
    382      * returned in the parts of the result according to the rules for
    383      * {@link java.lang.Double} arithmetic.
    384      *
    385      * @param rhs the other complex number
    386      * @return the complex number difference
    387      * @throws NullPointerException if <code>rhs</code> is null
    388      */
    389     public Complex subtract(Complex rhs) {
    390         if (isNaN() || rhs.isNaN()) {
    391             return NaN;
    392         }
    393
    394         return new Complex(real - rhs.getReal(),
    395             imaginary - rhs.getImaginary());
    396     }
    397 }