// Copyright (C) 2016 EDF
// All Rights Reserved
// This code is published under the GNU Lesser General Public License (GNU LGPL)
#ifndef INVNORMALCUMULATIVEDISTRIBUTION_H
#define INVNORMALCUMULATIVEDISTRIBUTION_H
#define _USE_MATH_DEFINES
#include <math.h>

/** \file InvNormalCumulativeDistribution.h
 * Calculate
 * \f[
 *     {1 \over { \sqrt{2 \pi}}}  \int_{\infty}^d e^{-x^2/2} dx
 * \f]
 * \author Xavier Warin
 */

/// \class InvNormalCumulativeDistribution  InvNormalCumulativeDistribution.h
///  Calculate the inverse of a Normal Cumulative distribution
class InvNormalCumulativeDistribution
{
public :
    /// \brief constructor
    InvNormalCumulativeDistribution() {};

    /// \brief calculate the vale function
    /// \param  p_x point where the function is evaluated
    /// \return function value;
    double operator()(const double   &p_x) const
    {

        double a0 = 2.50662823884 ;
        double a1 = -18.61500062529 ;
        double a2 = 41.39119773534 ;
        double a3 = -25.44106049637 ;
        double b0 = -8.47351093090;
        double b1 = 23.08336743743;
        double b2 = -21.06224101826;
        double b3 = 3.13082909833;
        double c0 = 0.3374754822726147;
        double c1 = 0.9761690190917186;
        double c2 = 0.1607979714918209;
        double c3 = 0.0276438810333863;
        double c4 = 0.0038405729373609;
        double c5 = 0.0003951896511919;
        double c6 = 0.0000321767881768;
        double c7 = 0.0000002888167364;
        double c8 = 0.0000003960315187;

        double y =  p_x - 0.5 ;
        if (fabs(y) < 0.42)
        {
            double r = y * y ;
            double x =  y * (((a3 * r + a2) * r + a1) * r + a0) / ((((b3 * r + b2) * r + b1) * r + b0) * r + 1);
            return x;
        }
        else
        {
            double r = p_x;
            if (y > 0)r = 1 - p_x;
            r = log(-log(r));
            double  x = c0 + r * (c1 + r * (c2 + r * (c3 + r * (c4 + r * (c5 + r * (c6 + r * (c7 + r * c8)))))));
            if (y < 0) x = -x;
            return x ;
        }
    }
};
#endif
