Пример #1
0
        private static Complex LogGamma_Stirling(Complex z)
        {
            // work in the upper complex plane; i think this isn't actually necessary
            //if (z.Im < 0.0) return (LogGamma_Stirling(z.Conjugate).Conjugate);

            Complex f = (z - 0.5) * ComplexMath.Log(z) - z + 0.5 * Math.Log(Global.TwoPI);

            // reduce f.Im modulo 2*PI
            // result is cyclic in f.Im modulo 2*PI, but if f.Im starts off too big, the corrections
            // applied below will be lost because they are being added to a big number
            //f = new Complex(f.Re, AdvancedMath.Reduce(f.Im, 0.0));
            // we should still do an optional reduction by 2 pi so that we get phase of Gamma right even
            // for large z.

            Complex zz = ComplexMath.Sqr(z);
            Complex zp = z;

            for (int i = 1; i < AdvancedIntegerMath.Bernoulli.Length; i++)
            {
                Complex f_old = f;
                f += AdvancedIntegerMath.Bernoulli[i] / ((2 * i) * (2 * i - 1)) / zp;
                if (f == f_old)
                {
                    return(f);
                }
                zp *= zz;
            }
            throw new NonconvergenceException();
        }
Пример #2
0
        private static Complex LogGamma_Stirling(Complex z)
        {
            // work in the upper complex plane; i think this isn't actually necessary
            if (z.Im < 0.0)
            {
                return(LogGamma_Stirling(z.Conjugate).Conjugate);
            }

            Complex f = (z - 0.5) * ComplexMath.Log(z) - z + Math.Log(Global.TwoPI) / 2.0;

            // reduce f.Im modulo 2*PI
            // result is cyclic in f.Im modulo 2*PI, but if f.Im starts off too big, the corrections
            // applied below will be lost because they are being added to a big number
            f = new Complex(f.Re, AdvancedMath.Reduce(f.Im, 0.0));

            Complex zz = z * z;
            Complex zp = z;

            for (int i = 1; i < AdvancedIntegerMath.Bernoulli.Length; i++)
            {
                Complex f_old = f;
                f += AdvancedIntegerMath.Bernoulli[i] / (2 * i) / (2 * i - 1) / zp;
                if (f == f_old)
                {
                    return(f);
                }
                zp *= zz;
            }
            throw new NonconvergenceException();
        }
Пример #3
0
        private static Complex DiLog_Series_1(Complex e)
        {
            Complex f = Math.PI * Math.PI / 6.0;

            if (e == 0.0)
            {
                return(f);
            }

            Complex L  = ComplexMath.Log(e);
            Complex ek = 1.0;

            for (int k = 1; k < Global.SeriesMax; k++)
            {
                Complex f_old = f;
                ek *= e;
                Complex df = ek * (L - 1.0 / k) / k;
                f += df;
                if (f == f_old)
                {
                    return(f);
                }
            }
            throw new NonconvergenceException();
        }
Пример #4
0
        public static Complex LogGamma(Complex z)
        {
            Complex t = z + LanczosGP;

            return(
                Math.Log(Global.SqrtTwoPI) +
                (z - 0.5) * ComplexMath.Log(t) - t +
                ComplexMath.Log(Sum(z))
                );
        }
Пример #5
0
        /// <summary>
        /// Computes the complex dilogarithm function, also called Spence's function.
        /// </summary>
        /// <param name="z">The complex argument.</param>
        /// <returns>The value Li<sub>2</sub>(z).</returns>
        /// <remarks>
        /// <para>This function is the analytic continuation of the dilogarithm function (<see cref="AdvancedMath.DiLog"/>) into the complex plane.</para>
        /// <para>The image below shows the complex dilogarithm function near the origin, using domain coloring.</para>
        /// <img src="../images/ComplexDiLogPlot.png" />
        /// </remarks>
        /// <seealso cref="AdvancedMath.DiLog"/>
        /// <seealso href="http://mathworld.wolfram.com/Dilogarithm.html" />
        public static Complex DiLog(Complex z)
        {
            Complex f;
            double  a0 = ComplexMath.Abs(z);

            if (a0 > 1.0)
            {
                // outside the unit disk, reflect into the unit disk
                Complex ln = ComplexMath.Log(-z);
                f = -Math.PI * Math.PI / 6.0 - ln * ln / 2.0 - DiLog(1.0 / z);
            }
            else
            {
                // inside the unit disk...
                if (a0 < 0.75)
                {
                    // close to 0, use the expansion about zero
                    f = DiLog_Series_0(z);
                }
                else
                {
                    // we are in the annulus near the edge of the unit disk
                    if (z.Re < 0.0)
                    {
                        // reflect negative into positive half-disk
                        // this avoids problems with the log expansion near -1
                        f = DiLog(z * z) / 2.0 - DiLog(-z);
                    }
                    else
                    {
                        // figure out whether we are close to 1
                        Complex e = 1.0 - z;
                        if (ComplexMath.Abs(e) < 0.5)
                        {
                            // close to 1, use the expansion about 1
                            f = DiLog_Series_1(e);
                        }
                        else
                        {
                            // otherwise, use the log expansion, which is good
                            // near the unit circle but not too close to 1 or -1
                            f = DiLog_Log_Series(z);
                        }
                    }
                }
            }

            if ((z.Re > 1.0) && (Math.Sign(f.Im) != Math.Sign(z.Im)))
            {
                f = f.Conjugate;
            }

            return(f);
        }
Пример #6
0
        public void TestLog()
        {
            Complex arg;
            Complex result;

            arg = new Complex(1 / 2.0, 1 / 3.0);

            Assert.AreEqual(0.6009252125773315488532035, arg.GetModulus(), 1e-15);

            result = ComplexMath.Log(arg);
            Assert.AreEqual(-0.5092847904972866327857336, result.Re, 1e-15);
            Assert.AreEqual(0.5880026035475675512456111, result.Im, 1e-15);
        }
Пример #7
0
        private static Complex LogGammaReflectionTerm(Complex z)
        {
            // s will overflow for large z.Im, but we are taking its log, so we should
            // re-formulate this
            Complex s    = new Complex(MoreMath.SinPi(z.Re) * Math.Cosh(Math.PI * z.Im), MoreMath.CosPi(z.Re) * Math.Sinh(Math.PI * z.Im));
            Complex logs = ComplexMath.Log(s);

            double m1 = Math.Log(MoreMath.Hypot(MoreMath.SinPi(z.Re), Math.Sinh(Math.PI * z.Im)));

            double t  = Math.Abs(Math.PI * z.Im);
            double c1 = Math.Exp(-2.0 * t);
            double c2 = MoreMath.SinPi(z.Re) / Math.Sinh(t);
            double m2 = t + MoreMath.LogOnePlus(-c1) + 0.5 * MoreMath.LogOnePlus(c2 * c2) - Math.Log(2.0);

            return(Math.Log(Math.PI) - logs);
        }
Пример #8
0
        public void Log()
        {
            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.Log(cd1);

            Assert.AreEqual(cdt.Real, 0.900, TOLERENCE);
            Assert.AreEqual(cdt.Imag, -1.107, TOLERENCE);

            cdt = ComplexMath.Log(cd2);
            Assert.AreEqual(cdt.Real, 0.788, TOLERENCE);
            Assert.AreEqual(cdt.Imag, -1.571, TOLERENCE);

            cdt = ComplexMath.Log(cd3);
            Assert.AreEqual(cdt.Real, 0.0953, TOLERENCE);
            Assert.AreEqual(cdt.Imag, 0, TOLERENCE);

            cdt = ComplexMath.Log(cd4);
            Assert.AreEqual(cdt.Real, 0.900, TOLERENCE);
            Assert.AreEqual(cdt.Imag, 2.034, TOLERENCE);

            ComplexFloat cft = ComplexMath.Log(cf1);

            Assert.AreEqual(cft.Real, 0.900, TOLERENCE);
            Assert.AreEqual(cft.Imag, -1.107, TOLERENCE);

            cft = ComplexMath.Log(cf2);
            Assert.AreEqual(cft.Real, 0.788, TOLERENCE);
            Assert.AreEqual(cft.Imag, -1.571, TOLERENCE);

            cft = ComplexMath.Log(cf3);
            Assert.AreEqual(cft.Real, 0.095, TOLERENCE);
            Assert.AreEqual(cft.Imag, 0, TOLERENCE);

            cft = ComplexMath.Log(cf4);
            Assert.AreEqual(cft.Real, 0.900, TOLERENCE);
            Assert.AreEqual(cft.Imag, 2.034, TOLERENCE);
        }
Пример #9
0
 /// <summary>
 /// Compute the complex log Gamma function.
 /// </summary>
 /// <param name="z">The complex argument.</param>
 /// <returns>The principal complex value y for which exp(y) = &#x393;(z).</returns>
 /// <seealso cref="AdvancedMath.LogGamma" />
 /// <seealso href="http://mathworld.wolfram.com/LogGammaFunction.html"/>
 public static Complex LogGamma(Complex z)
 {
     if (z.Im == 0.0 && z.Re < 0.0)
     {
         // Handle the pure negative case explicitly.
         double re = Math.Log(Math.PI / Math.Abs(MoreMath.SinPi(z.Re))) - AdvancedMath.LogGamma(1.0 - z.Re);
         double im = Math.PI * Math.Floor(z.Re);
         return(new Complex(re, im));
     }
     else if (z.Re > 16.0 || Math.Abs(z.Im) > 16.0)
     {
         // According to https://dlmf.nist.gov/5.11, the Stirling asymptoic series is valid everywhere
         // except on the negative real axis. So at first I tried to use it for |z.Im| > 0, |z| > 16. But in practice,
         // it exhibits false convergence close to the negative real axis, e.g. z = -16 + i. So I have
         // moved to requiring |z| large and reasonably far from the negative real axis.
         return(Stirling.LogGamma(z));
     }
     else if (z.Re >= 0.125)
     {
         return(Lanczos.LogGamma(z));
     }
     else
     {
         // For the remaining z < 0, we need to use the reflection formula.
         // For large z.Im, SinPi(z) \propto e^{\pi |z.Im|} overflows even though its log does not.
         // It's possible to do some algebra to get around that problem, but it's not necessary
         // because for z.Im that big we would have used the Stirling series.
         Complex f = ComplexMath.Log(Math.PI / ComplexMath.SinPi(z));
         Complex g = Lanczos.LogGamma(1.0 - z);
         // The reflection formula doesn't stay on the principal branch, so we need to add a multiple of 2 \pi i
         // to fix it up. See Hare, "Computing the Principal Branch of Log Gamma" for how to do this.
         // https://pdfs.semanticscholar.org/1c9d/8865836a312836500126cb47c3cbbed3043e.pdf
         Complex h = new Complex(0.0, 2.0 * Math.PI * Math.Floor(0.5 * (z.Re + 0.5)));
         if (z.Im < 0.0)
         {
             h = -h;
         }
         return(f - g + h);
     }
 }
Пример #10
0
        private static Complex DiLog_Log_Series(Complex z)
        {
            Complex ln  = ComplexMath.Log(z);
            Complex ln2 = ln * ln;

            Complex f = Math.PI * Math.PI / 6.0 + ln * (1.0 - ComplexMath.Log(-ln)) - ln2 / 4.0;

            Complex p = ln;

            for (int k = 1; k < AdvancedIntegerMath.Bernoulli.Length; k++)
            {
                Complex f_old = f;
                p *= ln2 / (2 * k + 1) / (2 * k);
                f += (-AdvancedIntegerMath.Bernoulli[k] / (2 * k)) * p;
                if (f == f_old)
                {
                    return(f);
                }
            }

            throw new NonconvergenceException();
        }
Пример #11
0
        public void EvaluateGradient(double[] X, double[] P, double[][] DY)
        {
            double x = X[0];

            if (_useFrequencyInsteadOmega)
            {
                x *= (2 * Math.PI);
            }

            DY[0][0] = 1;
            DY[1][0] = 0;

            Complex OneByDenom = 1 / ComplexMath.Pow(1 + ComplexMath.Pow(Complex.I * x * P[2], P[3]), P[4]);

            DY[0][1] = OneByDenom.Re;
            DY[1][1] = -OneByDenom.Im;
            Complex IXP2      = Complex.I * x * P[2];
            Complex IXP2PowP3 = ComplexMath.Pow(IXP2, P[3]);
            Complex der2      = OneByDenom * -P[1] * P[2] * P[4] * IXP2PowP3 / (P[2] * (1 + IXP2PowP3));

            DY[0][2] = der2.Re;
            DY[1][2] = -der2.Im;
            Complex der3 = OneByDenom * -P[1] * P[4] * IXP2PowP3 *ComplexMath.Log(IXP2) / (1 + IXP2PowP3);

            DY[0][3] = der3.Re;
            DY[1][3] = -der3.Im;
            Complex der4 = OneByDenom * -P[1] * ComplexMath.Log(1 + IXP2PowP3);

            DY[0][4] = der4.Re;
            DY[1][4] = -der4.Im;

            if (_useFlowTerm)
            {
                DY[0][5] = 0;
                DY[1][5] = _isDielectricData ?  1 / (x * 8.854187817e-12) : 1 / x;
            }
        }
Пример #12
0
 /// <summary>
 /// Computes the entire complex exponential integral.
 /// </summary>
 /// <param name="z">The complex argument.</param>
 /// <returns>The value of Ein(z).</returns>
 /// <remarks>
 /// <para>The entire exponential integral function can be defined by an integral or an equivalent series.</para>
 /// <img src="..\images\EinIntegralSeries.png" />
 /// <para>Both Ei(x) and E<sub>1</sub>(z) can be obtained from Ein(z).</para>
 /// <img src="..\images\E1EiEinRelation.png" />
 /// <para>Unlike either Ei(x) or E<sub>1</sub>(z), Ein(z) is entire, that is, it has no poles or cuts anywhere
 /// in the complex plane.</para>
 /// </remarks>
 /// <seealso cref="AdvancedMath.IntegralEi(double)"/>
 /// <seealso cref="AdvancedMath.IntegralE(int, double)"/>
 public static Complex Ein(Complex z)
 {
     if (z.Re < -40.0)
     {
         // For sufficiently negative z, use the asymptotic expansion for Ei
         return(AdvancedMath.EulerGamma + ComplexMath.Log(-z) - IntegralEi_AsymptoticSeries(-z));
     }
     else
     {
         // Ideally, we would like to use the series within some simple radius of the origin and the continued fraction
         // outside it. That works okay for the right half-plane, but for z.Re < 0 we have to contend with the fact that the
         // continued fraction fails on or near the negative real axis. That makes us use the series in an oddly shaped
         // region that extends much further from the origin than we would like into the left half-plane. It would be
         // great if we could find an alternative approach in that region.
         if (IsEinSeriesPrefered(z))
         {
             return(Ein_Series(z));
         }
         else
         {
             return(AdvancedMath.EulerGamma + ComplexMath.Log(z) + IntegeralE1_ContinuedFraction(z));
         }
     }
 }
Пример #13
0
 public static Complex LogGamma(Complex z)
 {
     return((z - 0.5) * ComplexMath.Log(z) - z + halfLogTwoPi + Sum(z));
 }
Пример #14
0
        public static Complex Psi(Complex z)
        {
            Complex t = z + LanczosGP;

            return(ComplexMath.Log(t) - LanczosG / t + LogSumPrime(z));
        }