Normal distribution functions.
References: Cephes Math Library, http://www.netlib.org/cephes/ George Marsaglia, Evaluating the Normal Distribution, 2004. Available in: http://www.jstatsoft.org/v11/a05/paper
Exemplo n.º 1
0
        /// <summary>
        ///   Inverse of incomplete beta integral.
        /// </summary>
        ///
        /// <example>
        ///   Please see <see cref="Beta"/>
        /// </example>
        ///
        public static double IncompleteInverse(double aa, double bb, double yy0)
        {
            double a, b, y0, d, y, x, x0, x1, lgm, yp, di, dithresh, yl, yh;
            int    i, dir;

            bool nflg;
            bool rflg;


            if (yy0 <= 0)
            {
                return(0.0);
            }
            if (yy0 >= 1.0)
            {
                return(1.0);
            }

            if (aa <= 1.0 || bb <= 1.0)
            {
                nflg     = true;
                dithresh = 4.0 * Constants.DoubleEpsilon;
                rflg     = false;
                a        = aa;
                b        = bb;
                y0       = yy0;
                x        = a / (a + b);
                y        = Incomplete(a, b, x);
                goto ihalve;
            }
            else
            {
                nflg     = false;
                dithresh = 1.0e-4;
            }

            /* approximation to inverse function */

            yp = -Normal.Inverse(yy0);

            if (yy0 > 0.5)
            {
                rflg = true;
                a    = bb;
                b    = aa;
                y0   = 1.0 - yy0;
                yp   = -yp;
            }
            else
            {
                rflg = false;
                a    = aa;
                b    = bb;
                y0   = yy0;
            }

            lgm = (yp * yp - 3.0) / 6.0;
            x0  = 2.0 / (1.0 / (2.0 * a - 1.0) + 1.0 / (2.0 * b - 1.0));
            y   = yp * Math.Sqrt(x0 + lgm) / x0
                  - (1.0 / (2.0 * b - 1.0) - 1.0 / (2.0 * a - 1.0))
                  * (lgm + 5.0 / 6.0 - 2.0 / (3.0 * x0));
            y = 2.0 * y;

            if (y < Constants.LogMin)
            {
                x0 = 1.0;
                throw new ArithmeticException("underflow");
            }

            x  = a / (a + b * Math.Exp(y));
            y  = Incomplete(a, b, x);
            yp = (y - y0) / y0;

            if (Math.Abs(yp) < 1.0e-2)
            {
                goto newt;
            }

ihalve:

            /* Resort to interval halving if not close enough */
            x0  = 0.0;
            yl  = 0.0;
            x1  = 1.0;
            yh  = 1.0;
            di  = 0.5;
            dir = 0;

            for (i = 0; i < 400; i++)
            {
                if (i != 0)
                {
                    x = x0 + di * (x1 - x0);
                    if (x == 1.0)
                    {
                        x = 1.0 - Constants.DoubleEpsilon;
                    }
                    y  = Incomplete(a, b, x);
                    yp = (x1 - x0) / (x1 + x0);
                    if (Math.Abs(yp) < dithresh)
                    {
                        x0 = x;
                        goto newt;
                    }
                }

                if (y < y0)
                {
                    x0 = x;
                    yl = y;
                    if (dir < 0)
                    {
                        dir = 0;
                        di  = 0.5;
                    }
                    else if (dir > 1)
                    {
                        di = 0.5 * di + 0.5;
                    }
                    else
                    {
                        di = (y0 - y) / (yh - yl);
                    }
                    dir += 1;
                    if (x0 > 0.75)
                    {
                        if (rflg)
                        {
                            rflg = false;
                            a    = aa;
                            b    = bb;
                            y0   = yy0;
                        }
                        else
                        {
                            rflg = true;
                            a    = bb;
                            b    = aa;
                            y0   = 1.0 - yy0;
                        }
                        x = 1.0 - x;
                        y = Incomplete(a, b, x);
                        goto ihalve;
                    }
                }
                else
                {
                    x1 = x;
                    if (rflg && x1 < Constants.DoubleEpsilon)
                    {
                        x0 = 0.0;
                        goto done;
                    }
                    yh = y;
                    if (dir > 0)
                    {
                        dir = 0;
                        di  = 0.5;
                    }
                    else if (dir < -1)
                    {
                        di = 0.5 * di;
                    }
                    else
                    {
                        di = (y - y0) / (yh - yl);
                    }
                    dir -= 1;
                }
            }

            if (x0 >= 1.0)
            {
                x0 = 1.0 - Constants.DoubleEpsilon;
                goto done;
            }

            if (x == 0.0)
            {
                throw new ArithmeticException("underflow");
            }

newt:

            if (nflg)
            {
                goto done;
            }

            x0  = x;
            lgm = Gamma.Log(a + b) - Gamma.Log(a) - Gamma.Log(b);

            for (i = 0; i < 10; i++)
            {
                /* Compute the function at this point. */
                if (i != 0)
                {
                    y = Incomplete(a, b, x0);
                }

                /* Compute the derivative of the function at this point. */
                d = (a - 1.0) * Math.Log(x0) + (b - 1.0) * Math.Log(1.0 - x0) + lgm;

                if (d < Constants.LogMin)
                {
                    throw new ArithmeticException("underflow");
                }

                d = Math.Exp(d);

                /* compute the step to the next approximation of x */
                d  = (y - y0) / d;
                x  = x0;
                x0 = x0 - d;

                if (x0 <= 0.0)
                {
                    throw new ArithmeticException("underflow");
                }

                if (x0 >= 1.0)
                {
                    x0 = 1.0 - Constants.DoubleEpsilon;
                    goto done;
                }

                if (Math.Abs(d / x0) < 64.0 * Constants.DoubleEpsilon)
                {
                    goto done;
                }
            }

done:
            if (rflg)
            {
                if (x0 <= Double.Epsilon)
                {
                    x0 = 1.0 - Double.Epsilon;
                }
                else
                {
                    x0 = 1.0 - x0;
                }
            }
            return(x0);
        }
Exemplo n.º 2
0
        /// <summary>
        ///   A function for computing bivariate normal probabilities.
        ///   BVND calculates the probability that X > DH and Y > DK.
        /// </summary>
        ///
        /// <remarks>
        /// <para>
        ///   This method is based on the work done by Alan Genz, Department of
        ///   Mathematics, Washington State University. Pullman, WA 99164-3113
        ///   Email: [email protected]. This work was shared under a 3-clause BSD
        ///   license. Please see source file for more details and the actual
        ///   license text.</para>
        ///
        /// <para>
        ///   This function is based on the method described by Drezner, Z and G.O.
        ///   Wesolowsky, (1989), On the computation of the bivariate normal integral,
        ///   Journal of Statist. Comput. Simul. 35, pp. 101-107, with major modifications
        ///   for double precision, and for |R| close to 1.</para>
        /// </remarks>
        ///
        private static double BVND(double dh, double dk, double r)
        {
            // Copyright (C) 2013, Alan Genz,  All rights reserved.
            //
            //  Redistribution and use in source and binary forms, with or without
            //  modification, are permitted provided the following conditions are met:
            //    1. Redistributions of source code must retain the above copyright
            //       notice, this list of conditions and the following disclaimer.
            //    2. Redistributions in binary form must reproduce the above copyright
            //       notice, this list of conditions and the following disclaimer in
            //       the documentation and/or other materials provided with the
            //       distribution.
            //    3. The contributor name(s) may not be used to endorse or promote
            //       products derived from this software without specific prior
            //       written permission.
            //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
            //  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
            //  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
            //  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
            //  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
            //  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
            //  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
            //  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
            //  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
            //  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF USE
            //  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

            const double TWOPI = 2.0 * Math.PI;

            double[] x;
            double[] w;

            if (Math.Abs(r) < 0.3)
            {
                // Gauss Legendre Points and Weights N =  6
                x = BVND_XN6;
                w = BVND_WN6;
            }
            else if (Math.Abs(r) < 0.75)
            {
                // Gauss Legendre Points and Weights N =  12
                x = BVND_XN12;
                w = BVND_WN12;
            }
            else
            {
                // Gauss Legendre Points and Weights N =  20
                x = BVND_XN20;
                w = BVND_WN20;
            }

            double h   = dh;
            double k   = dk;
            double hk  = h * k;
            double bvn = 0;

            if (Math.Abs(r) < 0.925)
            {
                if (Math.Abs(r) > 0)
                {
                    double sh  = (h * h + k * k) / 2;
                    double asr = Math.Asin(r);

                    for (int i = 0; i < x.Length; i++)
                    {
                        for (int j = -1; j <= 1; j += 2)
                        {
                            double sn = Math.Sin(asr * (j * x[i] + 1) / 2);
                            bvn = bvn + w[i] * Math.Exp((sn * hk - sh) / (1 - sn * sn));
                        }
                    }
                    bvn = bvn * asr / (2 * TWOPI);
                }

                return(bvn + Normal.Function(-h) * Normal.Function(-k));
            }


            if (r < 0)
            {
                k  = -k;
                hk = -hk;
            }

            if (Math.Abs(r) < 1)
            {
                double sa = (1 - r) * (1 + r);
                double A  = Math.Sqrt(sa);
                double sb = (h - k);
                sb = sb * sb;
                double c   = (4 - hk) / 8;
                double d   = (12 - hk) / 16;
                double asr = -(sb / sa + hk) / 2;

                if (asr > -100)
                {
                    bvn = A * Math.Exp(asr) * (1 - c * (sb - sa) * (1 - d * sb / 5) / 3 + c * d * sa * sa / 5);
                }

                if (-hk < 100)
                {
                    double B = Math.Sqrt(sb);
                    bvn = bvn - Math.Exp(-hk / 2) * Math.Sqrt(TWOPI) * Normal.Function(-B / A) * B
                          * (1 - c * sb * (1 - d * sb / 5) / 3);
                }

                A = A / 2;

                for (int i = 0; i < x.Length; i++)
                {
                    for (int j = -1; j <= 1; j += 2)
                    {
                        double xs = (A * (j * x[i] + 1));
                        xs = xs * xs;
                        double rs = Math.Sqrt(1 - xs);
                        asr = -(sb / xs + hk) / 2;

                        if (asr > -100)
                        {
                            bvn = bvn + A * w[i] * Math.Exp(asr)
                                  * (Math.Exp(-hk * xs / (2 * (1 + rs) * (1 + rs))) / rs
                                     - (1 + c * xs * (1 + d * xs)));
                        }
                    }
                }

                bvn = -bvn / TWOPI;
            }

            if (r > 0)
            {
                return(bvn + Normal.Function(-Math.Max(h, k)));
            }

            bvn = -bvn;

            if (k <= h)
            {
                return(bvn);
            }

            if (h < 0)
            {
                return(bvn + Normal.Function(k) - Normal.Function(h));
            }

            return(bvn + Normal.Function(-h) - Normal.Function(-k));
        }