Пример #1
0
        public void TestExp()
        {
            Complex result;

            result = ComplexMath.Exp(new Complex(0.5, 0.5));
            Assert.AreEqual(1.446889036584169158051583, result.Re, 1e-15);
            Assert.AreEqual(0.7904390832136149118432626, result.Im, 1e-15);
        }
Пример #2
0
 /// <summary>
 /// Computes the complex Gamma function.
 /// </summary>
 /// <param name="z">The complex argument.</param>
 /// <returns>The complex value of &#x393;(z).</returns>
 /// <remarks>
 /// <para>The image below shows the complex &#x393; function near the origin using domain coloring.</para>
 /// <img src="../images/ComplexGammaPlot.png" />
 /// </remarks>
 /// <seealso cref="AdvancedMath.Gamma(double)"/>
 /// <seealso href="http://en.wikipedia.org/wiki/Gamma_function" />
 /// <seealso href="http://mathworld.wolfram.com/GammaFunction.html" />
 public static Complex Gamma(Complex z)
 {
     if (z.Re < 0.5)
     {
         // 1-z form
         return(Math.PI / Gamma(1.0 - z) / ComplexMath.Sin(Math.PI * z));
         // -z form
         //return (-Math.PI / Gamma(-z) / z / ComplexMath.Sin(Math.PI * z));
     }
     return(ComplexMath.Exp(LogGamma(z)));
 }
        private static Complex IntegralEi_AsymptoticSeries(Complex z)
        {
            Complex dy = 1.0;
            Complex y  = dy;

            for (int k = 1; k < Global.SeriesMax; k++)
            {
                Complex y_old = y;
                dy = dy * k / z;
                y  = y_old + dy;
                if (y == y_old)
                {
                    return(ComplexMath.Exp(z) / z * y);
                }
            }
            throw new NonconvergenceException();
        }
Пример #4
0
 /// <summary>
 /// Computes the complex Gamma function.
 /// </summary>
 /// <param name="z">The complex argument.</param>
 /// <returns>The complex value of &#x393;(z).</returns>
 /// <remarks>
 /// <para>The image below shows the complex &#x393; function near the origin using domain coloring.</para>
 /// <img src="../images/ComplexGammaPlot.png" />
 /// </remarks>
 /// <seealso cref="AdvancedMath.Gamma(double)"/>
 /// <seealso href="http://en.wikipedia.org/wiki/Gamma_function" />
 /// <seealso href="http://mathworld.wolfram.com/GammaFunction.html" />
 public static Complex Gamma(Complex z)
 {
     if (z.Re < 0.5)
     {
         // 1-z form
         return(Math.PI / Gamma(1.0 - z) / ComplexMath.SinPi(z));
     }
     else if (ComplexMath.Abs(z) < 16.0)
     {
         return(Lanczos.Gamma(z));
     }
     else
     {
         // Add flag to do z-reduction
         return(ComplexMath.Exp(LogGamma_Stirling(z)));
     }
 }
Пример #5
0
        /// <summary>
        /// Computes the complex Faddeeva function.
        /// </summary>
        /// <param name="z">The complex argument.</param>
        /// <returns>The complex value of w(z).</returns>
        /// <remarks>
        /// <para>The Faddeeva function w(z) is related to the error function with a complex argument.</para>
        /// <img src="../images/FaddeevaErfcRelation.png" />
        /// <para>It also has an integral representation.</para>
        /// <img src="../images/FaddeevaIntegral.png" />
        /// <para>For purely imaginary values, it reduces to the complementary error function (<see cref="AdvancedMath.Erfc"/>).
        /// For purely real values, it reduces to Dawson's integral (<see cref="AdvancedMath.Dawson"/>).</para>
        /// <para>It appears in the computation of the Voigt line profile function V(x;&#x3C3;,&#x3B3;).</para>
        /// <img src="../images/Voigt.png" />
        /// <para>Near the origin, w(z) &#x2248; 1. To accurately determine w(z) - 1 in this region, use the <see cref="Erf"/>
        /// function. Away from the origin near the large negative imaginary axis, the magnitude w(z) increases rapidly and
        /// may overflow.</para>
        /// <para>The image below shows the complex Faddeeva function near the origin, using domain coloring.</para>
        /// <img src="../images/ComplexFaddeevaPlot.png" />
        /// </remarks>
        /// <seealso cref="AdvancedComplexMath.Erf"/>
        /// <seealso cref="AdvancedMath.Erf" />
        /// <seealso cref="AdvancedMath.Erfc" />
        /// <seealso cref="AdvancedMath.Dawson"/>
        /// <seealso href="http://en.wikipedia.org/wiki/Voigt_profile" />
        public static Complex Faddeeva(Complex z)
        {
            // use reflection formulae to ensure that we are in the first quadrant
            if (z.Im < 0.0)
            {
                return(2.0 * ComplexMath.Exp(-z * z) - Faddeeva(-z));
            }
            if (z.Re < 0.0)
            {
                return(Faddeeva(-z.Conjugate).Conjugate);
            }

            double r = ComplexMath.Abs(z);

            if (r < 2.0)
            {
                // use series for small z
                return(ComplexMath.Exp(-z * z) * (1.0 - Erf_Series(-ComplexMath.I * z)));
                //return (Faddeeva_Series(z));
            }
            else if ((z.Im < 0.1) && (z.Re < 30.0))
            {
                // this is a special, awkward region
                // along the real axis, Re{w(x)} ~ e^{-x^2}; the Weideman algorthm doesen't compute this small number
                // well and the Laplace continued fraction misses it entirely; therefore very close to the real axis
                // we will use an analytic result on the real axis and Taylor expand to where we need to go.
                // unfortunately the Taylor expansion converges poorly for large x, so we drop this work-arround near x~30,
                // when this real part becomes too small to represent as a double anyway
                double x = z.Re;
                double y = z.Im;
                return(Faddeeva_Taylor(new Complex(x, 0.0),
                                       Math.Exp(-x * x) + 2.0 * AdvancedMath.Dawson(x) / Global.SqrtPI * ComplexMath.I,
                                       new Complex(0.0, y)));
            }
            else if (r > 7.0)
            {
                // use Laplace continued fraction for large z
                return(Faddeeva_ContinuedFraction(z));
            }
            else
            {
                // use Weideman algorithm for intermediate region
                return(Faddeeva_Weideman(z));
            }
        }
Пример #6
0
        public void Exp()
        {
            Complex      cd1 = new Complex(1.1, -2.2);
            Complex      cd2 = new Complex(0, -2.2);
            Complex      cd3 = new Complex(1.1, 0);
            Complex      cd4 = new Complex(-1.1, 2.2);
            ComplexFloat cf1 = new ComplexFloat(1.1f, -2.2f);
            ComplexFloat cf2 = new ComplexFloat(0, -2.2f);
            ComplexFloat cf3 = new ComplexFloat(1.1f, 0);
            ComplexFloat cf4 = new ComplexFloat(-1.1f, 2.2f);

            Complex cdt = ComplexMath.Exp(cd1);

            Assert.AreEqual(cdt.Real, -1.768, TOLERENCE);
            Assert.AreEqual(cdt.Imag, -2.429, TOLERENCE);

            cdt = ComplexMath.Exp(cd2);
            Assert.AreEqual(cdt.Real, -0.589, TOLERENCE);
            Assert.AreEqual(cdt.Imag, -0.808, TOLERENCE);

            cdt = ComplexMath.Exp(cd3);
            Assert.AreEqual(cdt.Real, 3.004, TOLERENCE);
            Assert.AreEqual(cdt.Imag, 0, TOLERENCE);

            cdt = ComplexMath.Exp(cd4);
            Assert.AreEqual(cdt.Real, -0.196, TOLERENCE);
            Assert.AreEqual(cdt.Imag, 0.269, TOLERENCE);

            ComplexFloat cft = ComplexMath.Exp(cf1);

            Assert.AreEqual(cft.Real, -1.768, TOLERENCE);
            Assert.AreEqual(cft.Imag, -2.429, TOLERENCE);

            cft = ComplexMath.Exp(cf2);
            Assert.AreEqual(cft.Real, -0.589, TOLERENCE);
            Assert.AreEqual(cft.Imag, -0.808, TOLERENCE);

            cft = ComplexMath.Exp(cf3);
            Assert.AreEqual(cft.Real, 3.004, TOLERENCE);
            Assert.AreEqual(cft.Imag, 0, TOLERENCE);

            cft = ComplexMath.Exp(cf4);
            Assert.AreEqual(cft.Real, -0.196, TOLERENCE);
            Assert.AreEqual(cft.Imag, 0.269, TOLERENCE);
        }
        // This continued fraction is valid for |z| >> 1, except close to the negative real axis.

        private static Complex IntegeralE1_ContinuedFraction(Complex z)
        {
            int     a  = 1;             // a_1
            Complex b  = z + 1.0;       // b_1
            Complex D  = 1.0 / b;       // D_1 = 1 / b_1 (denominator of a_1 / b_1)
            Complex Df = a / b;         // Df_1 = f_1 - f_0 = a_1 / b_1
            Complex f  = 0.0 + Df;      // f_1 = f_0 + Df_1 = b_0 + a_1 / b_1 (here b_0 = 0)

            for (int k = 1; k < Global.SeriesMax; k++)
            {
                Complex f_old = f;
                a  = -k * k;
                b += 2.0;
                D  = 1.0 / (b + a * D);
                Df = (b * D - 1.0) * Df;
                f += Df;
                if (f == f_old)
                {
                    return(ComplexMath.Exp(-z) * f);
                }
            }
            throw new NonconvergenceException();
        }
Пример #8
0
        public static Complex AiryAi_Asymptotic(Complex z)
        {
            Debug.Assert(ComplexMath.Abs(z) >= 9.0);

            if (z.Re >= 0.0)
            {
                Complex xi = 2.0 / 3.0 * ComplexMath.Pow(z, 3.0 / 2.0);
                Airy_Asymptotic_Subseries(xi, out Complex u0, out Complex v0, out Complex u1, out Complex v1);
                Complex e = ComplexMath.Exp(xi);
                Complex q = ComplexMath.Pow(z, 1.0 / 4.0);
                return(0.5 / Global.SqrtPI / q / e * u1);
            }
            else
            {
                z = -z;
                Complex xi = 2.0 / 3.0 * ComplexMath.Pow(z, 3.0 / 2.0);
                Airy_Asymptotic_Subseries(xi, out Complex u0, out Complex v0, out Complex u1, out Complex v1);
                Complex c = ComplexMath.Cos(xi);
                Complex s = ComplexMath.Sin(xi);

                throw new NotImplementedException();
            }
        }
Пример #9
0
        /// <summary>
        /// Computes the complex error function.
        /// </summary>
        /// <param name="z">The complex argument.</param>
        /// <returns>The value of erf(z).</returns>
        /// <remarks>
        /// <para>This function is the analytic continuation of the error function (<see cref="AdvancedMath.Erf"/>) to the complex plane.</para>
        /// <para>The image below shows the complex error function near the origin, using domain coloring.</para>
        /// <img src="../images/ComplexErfPlot.png" />
        /// <para>The complex error function is entire: it has no poles, cuts, or discontinuities anywhere in the complex plane.</para>
        /// <para>For pure imaginary arguments, erf(z) reduces to the Dawson integral (<see cref="AdvancedMath.Dawson"/>).</para>
        /// <para>Away from the origin near the real axis, the real part of erf(z) quickly approaches &#x0b1;1. To accurately determine
        /// the small difference erf(z) &#8723; 1 in this region, use the <see cref="Faddeeva"/> function. Away from the origin near
        /// the imaginary axis, the magnitude of erf(z) increases very quickly. Although erf(z) may overflow in this region, you
        /// can still accurately determine the value of the product erf(z) exp(z<sup>2</sup>) using the <see cref="Faddeeva"/>
        /// function.</para>
        /// </remarks>
        /// <seealso cref="AdvancedMath.Erf"/>
        /// <seealso cref="AdvancedMath.Dawson"/>
        /// <seealso cref="AdvancedComplexMath.Faddeeva"/>
        public static Complex Erf(Complex z)
        {
            double r = ComplexMath.Abs(z);

            if (r < 4.0)
            {
                // near the origin, use the series
                return(Erf_Series(z));
            }
            else
            {
                // otherwise, just compute from Faddeva
                if (z.Re < 0.0)
                {
                    // since Fadddeeva blows up for negative z.Re, use erf(z) = -erf(-z)
                    return(ComplexMath.Exp(-z * z) * Faddeeva(-ComplexMath.I * z) - 1.0);
                }
                else
                {
                    return(1.0 - ComplexMath.Exp(-z * z) * Faddeeva(ComplexMath.I * z));
                }
                // we don't do this near the origin beause we would loose accuracy in the very small real parts there by subtracting from 1
            }
        }
 private static Complex ComplexTestFunction(
     double x
     )
 {
     return(ComplexMath.Exp(new Complex(-x, -x)));
 }