/*
 * Copyright 2003-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * This code is modified for the MathEclipse project
 */

package org.matheclipse.core.expression;

import org.matheclipse.parser.client.math.MathUtils;

/**
 * Static implementations of common
 * {@link org.matheclipse.parser.client.math.Complex}-valued functions.  Included
 * are trigonometric, exponential, log, power and square root functions.
 *

* Reference: *

* See individual method javadocs for the computational formulas used. * In general, NaN values in either real or imaginary parts of input arguments * result in {@link ComplexNum#NaN} returned. Otherwise, infinite or NaN values * are returned as they arise in computing the real functions specified in the * computational formulas. Null arguments result in NullPointerExceptions. * * @version $Revision: 1.7 $ $Date: 2008/09/07 10:01:54 $ */ public class ComplexUtils { /** * Default constructor. */ private ComplexUtils() { super(); } /** * Compute the * * inverse cosine for the given complex argument. *

* Implements the formula:

     *  acos(z) = -i (log(z + i (sqrt(1 - z2))))
*

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN or infinite. * * @param z the value whose inverse cosine is to be returned * @return the inverse cosine of z * @throws NullPointerException if z is null */ public static ComplexNum acos(final ComplexNum z) { if (z.isNaN()) { return ComplexNum.NaN; } return ComplexNum.I.negate().multiply(log(z.add( ComplexNum.I.multiply(sqrt1z(z))))); } /** * Compute the * * inverse sine for the given complex argument. *

* Implements the formula:

     *  asin(z) = -i (log(sqrt(1 - z2) + iz)) 
*

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN or infinite. * * @param z the value whose inverse sine is to be returned. * @return the inverse sine of z. * @throws NullPointerException if z is null */ public static ComplexNum asin(final ComplexNum z) { if (z.isNaN()) { return ComplexNum.NaN; } return ComplexNum.I.negate().multiply(log(sqrt1z(z).add( ComplexNum.I.multiply(z)))); } /** * Compute the * * inverse tangent for the given complex argument. *

* Implements the formula:

     *  atan(z) = (i/2) log((i + z)/(i - z)) 
*

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN or infinite. * * @param z the value whose inverse tangent is to be returned * @return the inverse tangent of z * @throws NullPointerException if z is null */ public static ComplexNum atan(final ComplexNum z) { if (z.isNaN()) { return ComplexNum.NaN; } return ComplexNum.I.multiply( log(ComplexNum.I.add(z).divide(ComplexNum.I.subtract(z)))) .divide(ComplexNum.valueOf(2.0, 0.0)); } /** * Compute the * * cosine * for the given complex argument. *

* Implements the formula:

     *  cos(a + bi) = cos(a)cosh(b) - sin(a)sinh(b)i
* where the (real) functions on the right-hand side are * {@link java.lang.Math#sin}, {@link java.lang.Math#cos}, * {@link MathUtils#cosh} and {@link MathUtils#sinh}. *

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN. *

* Infinite values in real or imaginary parts of the input may result in * infinite or NaN values returned in parts of the result.

     * Examples:
     * 
     * cos(1 ± INFINITY i) = 1 ∓ INFINITY i
     * cos(±INFINITY + i) = NaN + NaN i
     * cos(±INFINITY ± INFINITY i) = NaN + NaN i
* * @param z the value whose cosine is to be returned * @return the cosine of z * @throws NullPointerException if z is null */ public static ComplexNum cos(final ComplexNum z) { if (z.isNaN()) { return ComplexNum.NaN; } final double a = z.getReal(); final double b = z.getImaginary(); return ComplexNum.valueOf(Math.cos(a) * MathUtils.cosh(b), -Math.sin(a) * MathUtils.sinh(b)); } /** * Compute the * * hyperbolic cosine for the given complex argument. *

* Implements the formula:

     *  cosh(a + bi) = cosh(a)cos(b) + sinh(a)sin(b)i
* where the (real) functions on the right-hand side are * {@link java.lang.Math#sin}, {@link java.lang.Math#cos}, * {@link MathUtils#cosh} and {@link MathUtils#sinh}. *

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN. *

* Infinite values in real or imaginary parts of the input may result in * infinite or NaN values returned in parts of the result.

     * Examples:
     * 
     * cosh(1 ± INFINITY i) = NaN + NaN i
     * cosh(±INFINITY + i) = INFINITY ± INFINITY i
     * cosh(±INFINITY ± INFINITY i) = NaN + NaN i
*

* Throws NullPointerException if z is null. * * @param z the value whose hyperbolic cosine is to be returned. * @return the hyperbolic cosine of z. */ public static ComplexNum cosh(final ComplexNum z) { if (z.isNaN()) { return ComplexNum.NaN; } final double a = z.getReal(); final double b = z.getImaginary(); return ComplexNum.valueOf(MathUtils.cosh(a) * Math.cos(b), MathUtils.sinh(a) * Math.sin(b)); } /** * Compute the * * exponential function for the given complex argument. *

* Implements the formula:

     *  exp(a + bi) = exp(a)cos(b) + exp(a)sin(b)i
* where the (real) functions on the right-hand side are * {@link java.lang.Math#exp}, {@link java.lang.Math#cos}, and * {@link java.lang.Math#sin}. *

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN. *

* Infinite values in real or imaginary parts of the input may result in * infinite or NaN values returned in parts of the result.

     * Examples:
     * 
     * exp(1 ± INFINITY i) = NaN + NaN i
     * exp(INFINITY + i) = INFINITY + INFINITY i
     * exp(-INFINITY + i) = 0 + 0i
     * exp(±INFINITY ± INFINITY i) = NaN + NaN i
*

* Throws NullPointerException if z is null. * * @param z the value * @return ez */ public static ComplexNum exp(final ComplexNum z) { if (z.isNaN()) { return ComplexNum.NaN; } final double b = z.getImaginary(); final double expA = Math.exp(z.getReal()); return ComplexNum.valueOf(expA * Math.cos(b), expA * Math.sin(b)); } /** * Compute the * * natural logarithm for the given complex argument. *

* Implements the formula:

     *  log(a + bi) = ln(|a + bi|) + arg(a + bi)i
* where ln on the right hand side is {@link java.lang.Math#log}, * |a + bi| is the modulus, {@link ComplexNum#abs}, and * arg(a + bi) = {@link java.lang.Math#atan2}(b, a) *

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN. *

* Infinite (or critical) values in real or imaginary parts of the input may * result in infinite or NaN values returned in parts of the result.

     * Examples:
     * 
     * log(1 ± INFINITY i) = INFINITY ± (π/2)i
     * log(INFINITY + i) = INFINITY + 0i
     * log(-INFINITY + i) = INFINITY + πi
     * log(INFINITY ± INFINITY i) = INFINITY ± (π/4)i
     * log(-INFINITY ± INFINITY i) = INFINITY ± (3π/4)i
     * log(0 + 0i) = -INFINITY + 0i
     * 
* Throws NullPointerException if z is null. * * @param z the value. * @return ln z. */ public static ComplexNum log(final ComplexNum z) { if (z.isNaN()) { return ComplexNum.NaN; } return ComplexNum.valueOf(Math.log(z.dabs()), Math.atan2(z.getImaginary(), z.getReal())); } /** * Creates a complex number from the given polar representation. *

* The value returned is r·ei·theta, * computed as r·cos(theta) + r·sin(theta)i *

* If either r or theta is NaN, or * theta is infinite, {@link ComplexNum#NaN} is returned. *

* If r is infinite and theta is finite, * infinite or NaN values may be returned in parts of the result, following * the rules for double arithmetic.

     * Examples:
     * 
     * polar2Complex(INFINITY, π/4) = INFINITY + INFINITY i
     * polar2Complex(INFINITY, 0) = INFINITY + NaN i
     * polar2Complex(INFINITY, -π/4) = INFINITY - INFINITY i
     * polar2Complex(INFINITY, 5π/4) = -INFINITY - INFINITY i 
* * @param r the modulus of the complex number to create * @param theta the argument of the complex number to create * @return r·ei·theta * @throws IllegalArgumentException if r is negative * @since 1.1 */ public static ComplexNum polar2Complex(final double r, final double theta) { if (r < 0) { throw new IllegalArgumentException ("DoubleComplexImpl modulus must not be negative"); } return ComplexNum.valueOf(r * Math.cos(theta), r * Math.sin(theta)); } /** * Returns of value of y raised to the power of x. *

* Implements the formula:

     *  yx = exp(x·log(y))
* where exp and log are {@link #exp} and * {@link #log}, respectively. *

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN or infinite, or if y * equals {@link ComplexNum#ZERO}. * * @param y the base. * @param x the exponent. * @return yx * @throws NullPointerException if either x or y is null */ public static ComplexNum pow(final ComplexNum y, final ComplexNum x) { return exp(x.multiply(log(y))); } /** * Compute the * * sine * for the given complex argument. *

* Implements the formula:

     *  sin(a + bi) = sin(a)cosh(b) - cos(a)sinh(b)i
* where the (real) functions on the right-hand side are * {@link java.lang.Math#sin}, {@link java.lang.Math#cos}, * {@link MathUtils#cosh} and {@link MathUtils#sinh}. *

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN. *

* Infinite values in real or imaginary parts of the input may result in * infinite or NaN values returned in parts of the result.

     * Examples:
     * 
     * sin(1 ± INFINITY i) = 1 ± INFINITY i
     * sin(±INFINITY + i) = NaN + NaN i
     * sin(±INFINITY ± INFINITY i) = NaN + NaN i
* * Throws NullPointerException if z is null. * * @param z the value whose sine is to be returned. * @return the sine of z. */ public static ComplexNum sin(final ComplexNum z) { if (z.isNaN()) { return ComplexNum.NaN; } final double a = z.getReal(); final double b = z.getImaginary(); return ComplexNum.valueOf(Math.sin(a) * MathUtils.cosh(b), Math.cos(a) * MathUtils.sinh(b)); } /** * Compute the * * hyperbolic sine for the given complex argument. *

* Implements the formula:

     *  sinh(a + bi) = sinh(a)cos(b)) + cosh(a)sin(b)i
* where the (real) functions on the right-hand side are * {@link java.lang.Math#sin}, {@link java.lang.Math#cos}, * {@link MathUtils#cosh} and {@link MathUtils#sinh}. *

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN. *

* Infinite values in real or imaginary parts of the input may result in * infinite or NaN values returned in parts of the result.

     * Examples:
     * 
     * sinh(1 ± INFINITY i) = NaN + NaN i
     * sinh(±INFINITY + i) = ± INFINITY + INFINITY i
     * sinh(±INFINITY ± INFINITY i) = NaN + NaN i
z
* @throws NullPointerException if z is null */ public static ComplexNum sinh(final ComplexNum z) { if (z.isNaN()) { return ComplexNum.NaN; } final double a = z.getReal(); final double b = z.getImaginary(); return ComplexNum.valueOf(MathUtils.sinh(a) * Math.cos(b), MathUtils.cosh(a) * Math.sin(b)); } /** * Compute the * * square root for the given complex argument. *

* Implements the following algorithm to compute sqrt(a + bi): *

  1. Let t = sqrt((|a| + |a + bi|) / 2)
  2. *
  3. if  a ≥ 0 return t + (b/2t)i
         *  else return |b|/2t + sign(b)t i 
  4. *
* where *

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN. *

* Infinite values in real or imaginary parts of the input may result in * infinite or NaN values returned in parts of the result.

     * Examples:
     * 
     * sqrt(1 ± INFINITY i) = INFINITY + NaN i
     * sqrt(INFINITY + i) = INFINITY + 0i
     * sqrt(-INFINITY + i) = 0 + INFINITY i
     * sqrt(INFINITY ± INFINITY i) = INFINITY + NaN i
     * sqrt(-INFINITY ± INFINITY i) = NaN ± INFINITY i
     * 
* * @param z the value whose square root is to be returned * @return the square root of z * @throws NullPointerException if z is null */ public static ComplexNum sqrt(final ComplexNum z) { if (z.isNaN()) { return ComplexNum.NaN; } final double a = z.getReal(); final double b = z.getImaginary(); final double t = Math.sqrt((Math.abs(a) + z.dabs()) / 2.0); if (a >= 0.0) { return ComplexNum.valueOf(t, b / (2.0 * t)); } else { return ComplexNum.valueOf(Math.abs(b) / (2.0 * t), MathUtils.indicator(b) * t); } } /** * Compute the * * square root of 1 - z2 for the given complex * argument. *

* Computes the result directly as * sqrt(DoubleComplexImpl.ONE.subtract(z.multiply(z))). *

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN. *

* Infinite values in real or imaginary parts of the input may result in * infinite or NaN values returned in parts of the result. * * @param z the value * @return the square root of 1 - z2 * @throws NullPointerException if z is null */ public static ComplexNum sqrt1z(final ComplexNum z) { return sqrt(ComplexNum.ONE.subtract(z.multiply(z))); } /** * Compute the * * tangent for the given complex argument. *

* Implements the formula:

     * tan(a + bi) = sin(2a)/(cos(2a)+cosh(2b)) + [sinh(2b)/(cos(2a)+cosh(2b))]i
* where the (real) functions on the right-hand side are * {@link java.lang.Math#sin}, {@link java.lang.Math#cos}, * {@link MathUtils#cosh} and {@link MathUtils#sinh}. *

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN. *

* Infinite (or critical) values in real or imaginary parts of the input may * result in infinite or NaN values returned in parts of the result.

     * Examples:
     * 
     * tan(1 ± INFINITY i) = 0 + NaN i
     * tan(±INFINITY + i) = NaN + NaN i
     * tan(±INFINITY ± INFINITY i) = NaN + NaN i
     * tan(±&pi/2 + 0 i) = ±INFINITY + NaN i
* * @param z the value whose tangent is to be returned * @return the tangent of z * @throws NullPointerException if z is null */ public static ComplexNum tan(final ComplexNum z) { if (z.isNaN()) { return ComplexNum.NaN; } final double a2 = 2.0 * z.getReal(); final double b2 = 2.0 * z.getImaginary(); final double d = Math.cos(a2) + MathUtils.cosh(b2); return ComplexNum.valueOf(Math.sin(a2) / d, MathUtils.sinh(b2) / d); } /** * Compute the * * hyperbolic tangent for the given complex argument. *

* Implements the formula:

     * tan(a + bi) = sinh(2a)/(cosh(2a)+cos(2b)) + [sin(2b)/(cosh(2a)+cos(2b))]i
* where the (real) functions on the right-hand side are * {@link java.lang.Math#sin}, {@link java.lang.Math#cos}, * {@link MathUtils#cosh} and {@link MathUtils#sinh}. *

* Returns {@link ComplexNum#NaN} if either real or imaginary part of the * input argument is NaN. *

* Infinite values in real or imaginary parts of the input may result in * infinite or NaN values returned in parts of the result.

     * Examples:
     * 
     * tanh(1 ± INFINITY i) = NaN + NaN i
     * tanh(±INFINITY + i) = NaN + 0 i
     * tanh(±INFINITY ± INFINITY i) = NaN + NaN i
     * tanh(0 + (&pi/2)i) = NaN + INFINITY i
* * @param z the value whose hyperbolic tangent is to be returned * @return the hyperbolic tangent of z * @throws NullPointerException if z is null */ public static ComplexNum tanh(final ComplexNum z) { if (z.isNaN()) { return ComplexNum.NaN; } final double a2 = 2.0 * z.getReal(); final double b2 = 2.0 * z.getImaginary(); final double d = MathUtils.cosh(a2) + Math.cos(b2); return ComplexNum.valueOf(MathUtils.sinh(a2) / d, Math.sin(b2) / d); } }

Ads help maintain this website.