예제 #1
0
        /// <summary>
        /// Computes the square root of a complex number.
        /// </summary>
        /// <param name="z">The argument.</param>
        /// <returns>The square root of the argument.</returns>
        /// <remarks>
        /// <para>The image below shows the complex square root function near the origin, using domain coloring.</para>
        /// <img src="../images/ComplexSqrtPlot.png" />
        /// <para>You can see the branch cut extending along the negative real axis from the zero at the origin.</para>
        /// </remarks>
        public static Complex Sqrt(Complex z)
        {
            if (z.Im == 0.0)
            {
                // Handle the degenerate case quickly.
                // This also eliminates need to worry about Im(z) = 0 in subsequent formulas.
                if (z.Re < 0.0)
                {
                    return(new Complex(0.0, Math.Sqrt(-z.Re)));
                }
                else
                {
                    return(new Complex(Math.Sqrt(z.Re), 0.0));
                }
            }
            else
            {
                // To find a fast formula for complex square root, note x + i y = \sqrt{a + i b} implies
                // x^2 + 2 i x y - y^2 = a + i b, so x^2 - y^2 = a and 2 x y = b. Cross-substitute and
                // use quadratic formula to solve for x^2 and y^2 to obtain
                //  x = \sqrt{\frac{\sqrt{a^2 + b^2} + a}{2}}  y = \pm \sqrt{\frac{\sqrt{a^2 + b^2} - a}{2}}
                // This gives complex square root in three square roots and a few flops.

                // Only problem is b << a case, where significant cancelation occurs in one of the formula.
                // (Which one depends on the sign of a.) Handle that case by series expansion.

                double p, q;
                if (Math.Abs(z.Im) < 0.25 * Math.Abs(z.Re))
                {
                    double x2 = MoreMath.Sqr(z.Im / z.Re);
                    double t  = x2 / 2.0;
                    double s  = t;
                    // Find s = \sqrt{1 + x^2} - 1 using binomial expansion
                    for (int k = 2; true; k++)
                    {
                        if (k > Global.SeriesMax)
                        {
                            throw new NonconvergenceException();
                        }
                        double s_old = s;
                        t *= (1.5 / k - 1.0) * x2;
                        s += t;
                        if (s == s_old)
                        {
                            break;
                        }
                    }
                    if (z.Re < 0.0)
                    {
                        p = -z.Re * s;
                        q = -2.0 * z.Re + p;
                    }
                    else
                    {
                        q = z.Re * s;
                        p = 2.0 * z.Re + q;
                    }
                }
                else
                {
                    double m = ComplexMath.Abs(z);
                    p = m + z.Re;
                    q = m - z.Re;
                }

                double x = Math.Sqrt(p / 2.0);
                double y = Math.Sqrt(q / 2.0);
                if (z.Im < 0.0)
                {
                    y = -y;
                }
                return(new Complex(x, y));

                /*
                 * if (Math.Abs(z.Im) < 0.125 * Math.Abs(z.Re)) {
                 *  // We should try to improve this by using a series instead of the full power algorithm.
                 *  return (Pow(z, 0.5));
                 * } else {
                 *  // This is a pretty fast formula for a complex square root, basically just
                 *  // three square roots and a few flops.
                 *  // But if z.Im << z.Re, then z.Re ~ m and it suffers from cancelations.
                 *  double m = Abs(z);
                 *  double x = Math.Sqrt((m + z.Re) / 2.0);
                 *  double y = Math.Sqrt((m - z.Re) / 2.0);
                 *  if (z.Im < 0.0) y = -y;
                 *  return (new Complex(x, y));
                 * }
                 */
            }
        }
예제 #2
0
        /// <summary>
        /// Raises a complex number to an integer power.
        /// </summary>
        /// <param name="z">The argument.</param>
        /// <param name="n">The power.</param>
        /// <returns>The value of z<sup>n</sup>.</returns>
        public static Complex Pow(Complex z, int n)
        {
            // this is a straight-up copy of MoreMath.Pow with x -> z, double -> Complex

            if (n < 0)
            {
                return(1.0 / Pow(z, -n));
            }

            switch (n)
            {
            case 0:
                // we follow convention that 0^0 = 1
                return(1.0);

            case 1:
                return(z);

            case 2:
                // 1 multiply
                return(z * z);

            case 3:
                // 2 multiplies
                return(z * z * z);

            case 4: {
                // 2 multiplies
                Complex z2 = z * z;
                return(z2 * z2);
            }

            case 5: {
                // 3 multiplies
                Complex z2 = z * z;
                return(z2 * z2 * z);
            }

            case 6: {
                // 3 multiplies
                Complex z2 = z * z;
                return(z2 * z2 * z2);
            }

            case 7: {
                // 4 multiplies
                Complex z3 = z * z * z;
                return(z3 * z3 * z);
            }

            case 8: {
                // 3 multiplies
                Complex z2 = z * z;
                Complex z4 = z2 * z2;
                return(z4 * z4);
            }

            case 9: {
                // 4 multiplies
                Complex z3 = z * z * z;
                return(z3 * z3 * z3);
            }

            case 10: {
                // 4 multiplies
                Complex z2 = z * z;
                Complex z4 = z2 * z2;
                return(z4 * z4 * z2);
            }

            default:
                return(ComplexMath.Pow(z, (double)n));
            }
        }
예제 #3
0
        /// <summary>
        /// Raises a complex number to an integer power.
        /// </summary>
        /// <param name="z">The argument.</param>
        /// <param name="n">The power.</param>
        /// <returns>The value of z<sup>n</sup>.</returns>
        public static Complex Pow(Complex z, int n)
        {
            if (n < 0)
            {
                return(1.0 / Pow(z, -n));
            }

            switch (n)
            {
            case 0:
                // We follow convention that 0^0 = 1
                return(1.0);

            case 1:
                return(z);

            case 2:
                // 1 multiply
                return(Sqr(z));

            case 3:
                // 2 multiplies
                return(Sqr(z) * z);

            case 4: {
                // 2 multiplies
                Complex z2 = Sqr(z);
                return(Sqr(z2));
            }

            case 5: {
                // 3 multiplies
                Complex z2 = Sqr(z);
                return(Sqr(z2) * z);
            }

            case 6: {
                // 3 multiplies
                Complex z2 = Sqr(z);
                return(Sqr(z2) * z2);
            }

            case 7: {
                // 4 multiplies
                Complex z3 = Sqr(z) * z;
                return(Sqr(z3) * z);
            }

            case 8: {
                // 3 multiplies
                Complex z2 = Sqr(z);
                Complex z4 = Sqr(z2);
                return(Sqr(z4));
            }

            case 9: {
                // 4 multiplies
                Complex z3 = Sqr(z) * z;
                return(Sqr(z3) * z3);
            }

            case 10: {
                // 4 multiplies
                Complex z2 = Sqr(z);
                Complex z4 = Sqr(z2);
                return(Sqr(z4) * z2);
            }

            case 12: {
                // 4 multiplies
                Complex z3 = Sqr(z) * z;
                Complex z6 = Sqr(z3);
                return(Sqr(z6));
            }

            case 16: {
                // 4 multiplies
                Complex z2 = Sqr(z);
                Complex z4 = Sqr(z2);
                Complex z8 = Sqr(z4);
                return(Sqr(z8));
            }

            // that's all the cases do-able in 4 or fewer complex multiplies
            default:
                return(ComplexMath.Pow(z, (double)n));
            }
        }