예제 #1
0
        /// <summary>
        /// This function returns the complex arctangent of the complex number
        /// a,  arctan(a)}. The branch cuts are on the imaginary axis,
        /// below  -i  and above  i .
        /// </summary>
        /// <param name="a">The function argument.</param>
        /// <returns>The complex arctangent of the complex number a.</returns>
        public static Complex Atan(Complex a)
        {
            double  R = a.Re, I = a.Im;
            Complex z;

            if (I == 0)
            {
                z = new Complex(Math.Atan(R), 0);
            }
            else
            {
                /* FIXME: This is a naive implementation which does not fully
                 *   take into account cancellation errors, overflow, underflow
                 *   etc.  It would benefit from the Hull et al treatment. */

                double r = hypot(R, I);

                double imag;

                double u = 2 * I / (1 + r * r);

                /* FIXME: the following cross-over should be optimized but 0.1
                 *   seems to work ok */

                if (Math.Abs(u) < 0.1)
                {
                    imag = 0.25 * (RMath.Log1p(u) - RMath.Log1p(-u));
                }
                else
                {
                    double A = hypot(R, I + 1);
                    double B = hypot(R, I - 1);
                    imag = 0.5 * Math.Log(A / B);
                }

                if (R == 0)
                {
                    if (I > 1)
                    {
                        z = new Complex(M_PI_2, imag);
                    }
                    else if (I < -1)
                    {
                        z = new Complex(-M_PI_2, imag);
                    }
                    else
                    {
                        z = new Complex(0, imag);
                    }
                }
                else
                {
                    z = new Complex(0.5 * Math.Atan2(2 * R, ((1 + r) * (1 - r))), imag);
                }
            }

            return(z);
        }
예제 #2
0
        /// <summary>
        /// Return log |z|.
        /// </summary>
        /// <param name="z">The complex function argument.</param>
        /// <returns>log |z|, i.e. the natural logarithm of the absolute value of z.</returns>
        public static double LogAbs(Complex z)
        {
            double xabs = Math.Abs(z.Re);
            double yabs = Math.Abs(z.Im);
            double max, u;

            if (xabs >= yabs)
            {
                max = xabs;
                u   = yabs / xabs;
            }
            else
            {
                max = yabs;
                u   = xabs / yabs;
            }

            // Handle underflow when u is close to 0
            return(Math.Log(max) + 0.5 * RMath.Log1p(u * u));
        }
예제 #3
0
        /// <summary>
        /// This function returns the complex arcsine of the complex number a,
        /// arcsin(a)}. The branch cuts are on the real axis, less than -1
        /// and greater than 1.
        /// </summary>
        /// <param name="a">The function argument.</param>
        /// <returns>the complex arcsine of the complex number a.</returns>
        public static Complex Asin(Complex a)
        {
            double  R = a.Re, I = a.Im;
            Complex z;

            if (I == 0)
            {
                z = Asin(R);
            }
            else
            {
                double x = Math.Abs(R), y = Math.Abs(I);
                double r = hypot(x + 1, y), s = hypot(x - 1, y);
                double A  = 0.5 * (r + s);
                double B  = x / A;
                double y2 = y * y;

                double real, imag;

                const double A_crossover = 1.5, B_crossover = 0.6417;

                if (B <= B_crossover)
                {
                    real = Math.Asin(B);
                }
                else
                {
                    if (x <= 1)
                    {
                        double D = 0.5 * (A + x) * (y2 / (r + x + 1) + (s + (1 - x)));
                        real = Math.Atan(x / Math.Sqrt(D));
                    }
                    else
                    {
                        double Apx = A + x;
                        double D   = 0.5 * (Apx / (r + x + 1) + Apx / (s + (x - 1)));
                        real = Math.Atan(x / (y * Math.Sqrt(D)));
                    }
                }

                if (A <= A_crossover)
                {
                    double Am1;

                    if (x < 1)
                    {
                        Am1 = 0.5 * (y2 / (r + (x + 1)) + y2 / (s + (1 - x)));
                    }
                    else
                    {
                        Am1 = 0.5 * (y2 / (r + (x + 1)) + (s + (x - 1)));
                    }

                    imag = RMath.Log1p(Am1 + Math.Sqrt(Am1 * (A + 1)));
                }
                else
                {
                    imag = Math.Log(A + Math.Sqrt(A * A - 1));
                }

                z = new Complex((R >= 0) ? real : -real, (I >= 0) ? imag : -imag);
            }

            return(z);
        }