Exemplo n.º 1
0
        // Elliptic integrals (complete and incomplete) of the second kind
        // Carlson, Numerische Mathematik, vol 33, 1 (1979)


        /// <summary>
        /// Returns the incomplete elliptic integral of the second kind D(φ, k)
        /// <para>D(φ, k) =  ∫ sin^2(θ)/sqrt(1-k^2*sin^2(θ)) dθ, θ={0,φ}</para>
        /// </summary>
        /// <param name="k">The modulus. Requires |k| ≤ 1</param>
        /// <param name="phi">The amplitude</param>
        public static double EllintD(double k, double phi)
        {
            if ((!(k >= -1 && k <= 1)) || (double.IsNaN(phi)))
            {
                Policies.ReportDomainError("EllintD(k: {0}, phi: {1}): Requires |k| <= 1; phi not NaN", k, phi);
                return(double.NaN);
            }
            if (double.IsInfinity(phi))
            {
                return(phi); // Note: result != phi, only +/- infinity
            }
            if (Math.Abs(phi) > Trig.PiReductionLimit)
            {
                Policies.ReportNotImplementedError("EllintD(k: {0}, phi: {1}): |phi| > {2} not implemented", k, phi, Trig.PiReductionLimit);
                return(double.NaN);
            }

            // special values
            //if (k == 0) // too much cancellation error near phi=0, general case works fine
            //    return (phi - Cos(phi)*Sin(phi))/2
            if (phi == 0)
            {
                return(0);
            }
            if (phi == Math.PI / 2)
            {
                return(Math2.EllintD(k));
            }

            // Carlson's algorithm works only for |phi| <= π/2,
            // use the integrand's periodicity to normalize phi
            // D(k, phi + π*mult) = D(k, phi) + 2*mult*D(k)

            double result = 0;
            double rphi   = Math.Abs(phi);

            if (rphi > Math.PI / 2)
            {
                // Normalize periodicity so that |rphi| <= π/2
                var(angleMultiple, angleRemainder) = Trig.RangeReducePI(rphi);
                double mult = 2 * angleMultiple;
                rphi = angleRemainder;
                if (mult != 0)
                {
                    result += mult * EllintD(k);
                }
            }

            double k2   = k * k;
            double sinp = Math.Sin(rphi);
            double cosp = Math.Cos(rphi);
            double x    = cosp * cosp;
            double t    = k2 * sinp * sinp;
            double y    = (t < 0.875) ? 1 - t : (1 - k2) + k2 * x;
            double z    = 1;

            // http://dlmf.nist.gov/19.25#E13
            // and RD(lambda*x, lambda*y, lambda*z) = lambda^(-3/2) * RD(x, y, z)
            result += EllintRD(x, y, z) * sinp * sinp * sinp / 3;

            return((phi < 0) ? -result : result);
        }