private static double GetGaussianQuantileRank(double x, double x0, double p0, double x1, double p1) { double mean, stddev; GetGaussianFromQuantiles(x0, p0, x1, p1, out mean, out stddev); return(MMath.NormalCdf((x - mean) / stddev)); }
public void NormalCdf2Test() { double x = 1.2, y = 1.3; double xy1 = System.Math.Max(0.0, MMath.NormalCdf(x) + MMath.NormalCdf(y) - 1); Assert.True(0 < MMath.NormalCdf(6.8419544775976187E-08, -5.2647906596206016E-08, -1, 3.1873689658872377E-10).Mantissa); // In sage: // integral(1/(2*pi*sqrt(1-t*t))*exp(-(x*x+y*y-2*t*x*y)/(2*(1-t*t))),t,-1,r).n(digits=200); double[,] normalcdf2_pairs = ReadPairs(Path.Combine(TestUtils.DataFolderPath, "SpecialFunctionsValues", "NormalCdf2.csv")); CheckFunctionValues("NormalCdf2", new MathFcn3(MMath.NormalCdf), normalcdf2_pairs); // using wolfram alpha: (for cases where r=-1 returns zero) // log(integrate(1/(2*pi*sqrt(1-t*t))*exp(-(2*0.1*0.1 - 2*t*0.1*0.1)/(2*(1-t*t))),t,-1,-0.9999)) // log(integrate(1/(2*pi*sqrt(1-t*t))*exp(-(2*1.5*1.5 + 2*t*1.5*1.5)/(2*(1-t*t))),t,-1,-0.5)) double[,] normalcdfln2_pairs = ReadPairs(Path.Combine(TestUtils.DataFolderPath, "SpecialFunctionsValues", "NormalCdfLn2.csv")); CheckFunctionValues("NormalCdfLn2", new MathFcn3(MMath.NormalCdfLn), normalcdfln2_pairs); double[,] normalcdfRatioLn2_pairs = ReadPairs(Path.Combine(TestUtils.DataFolderPath, "SpecialFunctionsValues", "NormalCdfRatioLn2.csv")); CheckFunctionValues("NormalCdfRatioLn2", new MathFcn4(NormalCdfRatioLn), normalcdfRatioLn2_pairs); // The true values are computed using // x * MMath.NormalCdf(x, y, r) + System.Math.Exp(Gaussian.GetLogProb(x, 0, 1) + MMath.NormalCdfLn(ymrx)) + r * System.Math.Exp(Gaussian.GetLogProb(y, 0, 1) + MMath.NormalCdfLn(xmry)) // where // ymrx = (y - r * x) / sqrt(1-r*r) // xmry = (x - r * y) / sqrt(1-r*r) double[,] normalcdfIntegral_pairs = ReadPairs(Path.Combine(TestUtils.DataFolderPath, "SpecialFunctionsValues", "NormalCdfIntegral.csv")); CheckFunctionValues("NormalCdfIntegral", new MathFcn3(MMath.NormalCdfIntegral), normalcdfIntegral_pairs); double[,] normalcdfIntegralRatio_pairs = ReadPairs(Path.Combine(TestUtils.DataFolderPath, "SpecialFunctionsValues", "NormalCdfIntegralRatio.csv")); CheckFunctionValues("NormalCdfIntegralRatio", new MathFcn3(MMath.NormalCdfIntegralRatio), normalcdfIntegralRatio_pairs); }
public double[] getbsdelta(double strike, double under, double volatility, double t, double rate)//calculate delta { double d1; double[] delta = new double[2]; d1 = (Math.Log(under / strike) + (rate + Math.Pow(volatility, 2) / 2) * t) / (volatility * Math.Sqrt(t)); delta[0] = MMath.NormalCdf(d1); //call delta delta[1] = delta[0] - 1; //put delta return(delta); }
public void NormalCdfTest() { /* In python mpmath: * from mpmath import * * mp.dps = 500 * mp.pretty = True * ncdf(-12.2) */ // In wolfram alpha: (not always accurate) // http://www.wolframalpha.com/input/?i=erfc%2813%2Fsqrt%282%29%29%2F2 // In xcas: (not always accurate) // Digits := 30 // phi(x) := evalf(erfc(-x/sqrt(2))/2); double[,] normcdf_pairs = ReadPairs(Path.Combine(TestUtils.DataFolderPath, "SpecialFunctionsValues", "NormalCdf.csv")); CheckFunctionValues("NormalCdf", new MathFcn(MMath.NormalCdf), normcdf_pairs); Assert.Equal(0.5, MMath.NormalCdf(0)); Assert.True(MMath.NormalCdf(7.9) <= 1); Assert.True(MMath.NormalCdf(-40) >= 0); Assert.True(MMath.NormalCdf(-80) >= 0); double[,] erfc_pairs = new double[normcdf_pairs.GetLength(0), normcdf_pairs.GetLength(1)]; for (int i = 0; i < normcdf_pairs.GetLength(0); i++) { double input = normcdf_pairs[i, 0]; double output = normcdf_pairs[i, 1]; erfc_pairs[i, 0] = -input / MMath.Sqrt2; erfc_pairs[i, 1] = 2 * output; } CheckFunctionValues("Erfc", new MathFcn(MMath.Erfc), erfc_pairs); double[,] normcdfinv_pairs = new double[normcdf_pairs.GetLength(0), 2]; for (int i = 0; i < normcdfinv_pairs.GetLength(0); i++) { double input = normcdf_pairs[i, 0]; double output = normcdf_pairs[i, 1]; if (!(Double.IsPositiveInfinity(input) || Double.IsNegativeInfinity(input)) && (input <= -10 || input >= 6)) { normcdfinv_pairs[i, 0] = 0.5; normcdfinv_pairs[i, 1] = 0; } else { normcdfinv_pairs[i, 0] = output; normcdfinv_pairs[i, 1] = input; } } CheckFunctionValues("NormalCdfInv", new MathFcn(MMath.NormalCdfInv), normcdfinv_pairs); double[,] normcdfln_pairs = ReadPairs(Path.Combine(TestUtils.DataFolderPath, "SpecialFunctionsValues", "NormalCdfLn.csv")); CheckFunctionValues("NormalCdfLn", new MathFcn(MMath.NormalCdfLn), normcdfln_pairs); double[,] normcdflogit_pairs = ReadPairs(Path.Combine(TestUtils.DataFolderPath, "SpecialFunctionsValues", "NormalCdfLogit.csv")); CheckFunctionValues("NormalCdfLogit", new MathFcn(MMath.NormalCdfLogit), normcdflogit_pairs); }
private double NormalCdfIntegralTaylor(double x, double y, double r) { double omr2 = 1 - r * r; double sqrtomr2 = System.Math.Sqrt(omr2); double ymrx = y / sqrtomr2; double dx0 = MMath.NormalCdf(0, y, r); double ddx0 = System.Math.Exp(Gaussian.GetLogProb(0, 0, 1) + MMath.NormalCdfLn(ymrx)); // \phi_{xx} &= -x \phi_x - r \phi_r double dddx0 = -r *System.Math.Exp(Gaussian.GetLogProb(0, 0, 1) + Gaussian.GetLogProb(ymrx, 0, 1)); Trace.WriteLine($"dx0 = {dx0} {ddx0} {dddx0}"); return(MMath.NormalCdfIntegral(0, y, r) + x * dx0 + 0.5 * x * x * ddx0 + 1.0 / 6 * x * x * x * dddx0); }
public static double NormalCdfMomentRecurrence(int n, double m, double v) { double prev = Math.Exp(-MMath.LnSqrt2PI - 0.5 * Math.Log(v) - 0.5 * m * m / v); double cur = MMath.NormalCdf(m / Math.Sqrt(v)); for (int i = 0; i < n; i++) { double next = (m * cur + v * prev) / (i + 1); prev = cur; cur = next; } return(cur); }
/// <summary> /// Gets the log of the normalizer for the Gaussian density function /// </summary> /// <returns></returns> public double GetLogNormalizer() { if (IsProper()) { // need to check this handles no truncation correctly double m = Gaussian.MeanTimesPrecision / Gaussian.Precision; double s = Math.Sqrt(1 / Gaussian.Precision); double Z = MMath.NormalCdf((UpperBound - m) / s) - MMath.NormalCdf((LowerBound - m) / s); return(MMath.LnSqrt2PI + 0.5 * (Gaussian.MeanTimesPrecision * Gaussian.MeanTimesPrecision / Gaussian.Precision - Math.Log(Gaussian.Precision)) + Math.Log(Z)); } else { return(0.0); } }
/// <summary> /// Compute the probability that a sample from this distribution is less than x. /// </summary> /// <param name="x">Any real number.</param> /// <returns>The cumulative gaussian distribution at <paramref name="x"/></returns> public double GetProbLessThan(double x) { if (this.IsPointMass) { return((this.Point < x) ? 1.0 : 0.0); } else if (Precision <= 0.0) { throw new ImproperDistributionException(this); } else { double sqrtPrec = Math.Sqrt(Precision); // (x - m)/sqrt(v) = x/sqrt(v) - m/v * sqrt(v) return(MMath.NormalCdf(x * sqrtPrec - MeanTimesPrecision / sqrtPrec)); } }
public void QuantileTest() { // draw many samples from N(m,v) Rand.Restart(0); int n = 10000; double m = 2; double stddev = 3; Gaussian prior = new Gaussian(m, stddev * stddev); List <double> x = new List <double>(); for (int i = 0; i < n; i++) { x.Add(prior.Sample()); } x.Sort(); var sortedData = new OuterQuantiles(x.ToArray()); // compute quantiles var quantiles = InnerQuantiles.FromDistribution(100, sortedData); // loop over x's and compare true quantile rank var testPoints = EpTests.linspace(MMath.Min(x) - stddev, MMath.Max(x) + stddev, 100); double maxError = 0; foreach (var testPoint in testPoints) { var trueRank = MMath.NormalCdf((testPoint - m) / stddev); var estRank = quantiles.GetProbLessThan(testPoint); var error = System.Math.Abs(trueRank - estRank); //Trace.WriteLine($"{testPoint} trueRank={trueRank} estRank={estRank} error={error}"); Assert.True(error < 0.02); maxError = System.Math.Max(maxError, error); double estQuantile = quantiles.GetQuantile(estRank); error = MMath.AbsDiff(estQuantile, testPoint, 1e-8); //Trace.WriteLine($"{testPoint} estRank={estRank} estQuantile={estQuantile} error={error}"); Assert.True(error < 1e-8); estRank = sortedData.GetProbLessThan(testPoint); error = System.Math.Abs(trueRank - estRank); //Trace.WriteLine($"{testPoint} trueRank={trueRank} estRank={estRank} error={error}"); Assert.True(error < 0.02); } //Trace.WriteLine($"max rank error = {maxError}"); }
private double NormalCdfIntegralBasic(double x, double y, double r) { double omr2 = 1 - r * r; double sqrtomr2 = System.Math.Sqrt(omr2); double ymrx = (y - r * x) / sqrtomr2; double xmry = (x - r * y) / sqrtomr2; // should use this whenever x > 0 and Rymrx >= Rxmry (y-r*x >= x-r*y implies y*(1+r) >= x*(1+r) therefore y >= x) // we need a special routine to compute 2nd half without cancellation and without dividing by phir // what about x > y > 0? //double t = MMath.NormalCdfIntegral(-x, y, -r) + x * MMath.NormalCdf(y) + r * System.Math.Exp(Gaussian.GetLogProb(y, 0, 1)); //Console.WriteLine(t); double phix = System.Math.Exp(Gaussian.GetLogProb(x, 0, 1) + MMath.NormalCdfLn(ymrx)); double phiy = System.Math.Exp(Gaussian.GetLogProb(y, 0, 1) + MMath.NormalCdfLn(xmry)); //Trace.WriteLine($"phix = {phix} phiy = {phiy}"); return(x * MMath.NormalCdf(x, y, r) + phix + r * phiy); //return y * MMath.NormalCdf(x, y, r) + r * System.Math.Exp(Gaussian.GetLogProb(x, 0, 1) + MMath.NormalCdfLn(ymrx)) + System.Math.Exp(Gaussian.GetLogProb(y, 0, 1) + MMath.NormalCdfLn(xmry)); }
internal void NormalCdfSpeedTest() { // current results: // NormalCdf(0.5): 28ms // NormalCdf2: 1974ms MMath.NormalCdf(0.5); double x = 1.5; MMath.NormalCdf(x, 0.5, 0.95); Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i < 100000; i++) { MMath.NormalCdf(0.5); } watch.Stop(); Console.WriteLine("NormalCdf(0.5): " + watch.ElapsedMilliseconds + "ms"); watch.Restart(); for (int i = 0; i < 100000; i++) { NormalCdf_Quadrature(x, 0.5, 0.1); } watch.Stop(); Console.WriteLine("NormalCdf2Quad: " + watch.ElapsedMilliseconds + "ms"); watch.Restart(); for (int i = 0; i < 100000; i++) { NormalCdfAlt(x, 0.5, 0.1); } watch.Stop(); Console.WriteLine("NormalCdf2Alt: " + watch.ElapsedMilliseconds + "ms"); watch.Restart(); for (int i = 0; i < 100000; i++) { MMath.NormalCdf(x, 0.5, 0.95); } watch.Stop(); Console.WriteLine("NormalCdf2: " + watch.ElapsedMilliseconds + "ms"); }
/// <summary> /// Compute int_0^Inf x^n N(x;m,v) dx for all integer n from 0 to nMax. Loses accuracy if m < -1. /// </summary> /// <param name="nMax"></param> /// <param name="m"></param> /// <param name="v"></param> /// <returns></returns> public static double[] NormalCdfMoments(int nMax, double m, double v) { double[] result = new double[nMax + 1]; double sqrtV = Math.Sqrt(v); double cur = MMath.NormalCdf(m / sqrtV); result[0] = cur; if (nMax > 0) { double prev = cur; cur = m * prev + sqrtV * Math.Exp(-MMath.LnSqrt2PI - 0.5 * m * m / v); result[1] = cur; for (int i = 1; i < nMax; i++) { double next = m * cur + v * prev * i; prev = cur; cur = next; result[i + 1] = cur; } } return(result); }
internal void NormalCdfIntegralTest2() { double x = 0.0093132267868981222; double y = -0.0093132247056551785; double r = -1; y = -2499147.006377392; x = 2499147.273918618; //MMath.TraceConFrac = true; //MMath.TraceConFrac2 = true; for (int i = 0; i < 100; i++) { //x = 2.1 * (i + 1); //y = -2 * (i + 1); //x = -2 * (i + 1); //y = 2.1 * (i + 1); //x = -System.Math.Pow(10, -i); //y = -x * 1.1; x = -0.33333333333333331; y = -1.5; r = 0.16666666666666666; x = -0.4999; y = 0.5; x = -0.1; y = 0.5; r = -0.1; x = -824.43680216388009; y = -23300.713731480908; r = -0.99915764591723821; x = -0.94102098773740084; x = 1 + i * 0.01; y = 2; r = 1; x = 0.021034851174404436; y = -0.37961242087533614; //x = -0.02; //y += -1; //x -= -1; r = -1 + System.Math.Pow(10, -i); //x = i * 0.01; //y = -1; //r = -1 + 1e-8; // 1.81377005549484E-40 with exponent // flipped is 1.70330340479022E-40 //x = -1; //y = -8.9473684210526319; //x = System.Math.Pow(10, -i); //y = x; //r = -0.999999999999999; //x = -0.94102098773740084; //y = -1.2461486442846208; //r = 0.5240076921033775; x = 790.80368892437889; y = -1081776354979.6719; y = -System.Math.Pow(10, i); r = -0.94587440643473975; x = -39062.492380206008; y = 39062.501110681893; r = -0.99999983334056686; //x = -2; //y = 1.5789473684210522; //r = -0.78947368421052622; //x = -1.1; //y = -1.1; //r = 0.052631578947368474; //x = 0.001; //y = -0.0016842105263157896; //r = -0.4; //x = 0.1; //x = 2000; //y = -2000; //r = -0.99999999999999989; x = double.MinValue; y = double.MinValue; r = 0.1; Trace.WriteLine($"(x,y,r) = {x:g17}, {y:g17}, {r:g17}"); double intZOverZ; try { intZOverZ = MMath.NormalCdfIntegralRatio(x, y, r); } catch { intZOverZ = double.NaN; } Trace.WriteLine($"intZOverZ = {intZOverZ:g17}"); double intZ0 = NormalCdfIntegralBasic(x, y, r); double intZ1 = 0; // NormalCdfIntegralFlip(x, y, r); double intZr = 0; // NormalCdfIntegralBasic2(x, y, r); ExtendedDouble intZ; double sqrtomr2 = System.Math.Sqrt((1 - r) * (1 + r)); try { intZ = MMath.NormalCdfIntegral(x, y, r, sqrtomr2); } catch { intZ = ExtendedDouble.NaN(); } //double intZ = intZ0; Trace.WriteLine($"intZ = {intZ:g17} {intZ.ToDouble():g17} {intZ0:g17} {intZ1:g17} {intZr:g17}"); if (intZ.Mantissa < 0) { throw new Exception(); } //double intZ2 = NormalCdfIntegralBasic(y, x, r); //Trace.WriteLine($"intZ2 = {intZ2} {r*intZ}"); double Z = MMath.NormalCdf(x, y, r); if (Z < 0) { throw new Exception(); } } }
/// <summary> /// Used to tune MMath.NormalCdfLn. The best tuning minimizes the number of messages printed. /// </summary> internal void NormalCdf2Test2() { // Call both routines now to speed up later calls. MMath.NormalCdf(-2, -2, -0.5); NormalCdf_Quadrature(-2, -2, -0.5); Stopwatch watch = new Stopwatch(); double xmin = 0.1; double xmax = 0.1; double n = 20; double xinc = (xmax - xmin) / (n - 1); for (int xi = 0; xi < n; xi++) { if (xinc == 0 && xi > 0) { break; } double x = xmin + xi * xinc; double ymin = -System.Math.Abs(x) * 10; double ymax = -ymin; double yinc = (ymax - ymin) / (n - 1); for (int yi = 0; yi < n; yi++) { double y = ymin + yi * yinc; double rmin = -0.999999; double rmax = -0.000001; rmin = MMath.NextDouble(-1); rmax = -1 + 1e-6; //rmax = -0.5; //rmax = 0.1; //rmax = -0.58; //rmax = -0.9; //rmin = -0.5; rmax = 1; double rinc = (rmax - rmin) / (n - 1); for (int ri = 0; ri < n; ri++) { double r = rmin + ri * rinc; string good = "good"; watch.Restart(); double result1 = double.NaN; try { result1 = MMath.NormalCdfIntegral(x, y, r); } catch { good = "bad"; //throw; } watch.Stop(); long ticks = watch.ElapsedTicks; watch.Restart(); double result2 = double.NaN; try { result2 = NormalCdfLn_Quadrature(x, y, r); } catch { } long ticks2 = watch.ElapsedTicks; bool overtime = ticks > 10 * ticks2; if (double.IsNaN(result1) /*|| overtime*/) { Trace.WriteLine($"({x:g17},{y:g17},{r:g17},{x - r * y}): {good} {ticks} {ticks2} {result1} {result2}"); } } } } }
/// <summary> /// Computes the cumulative bivariate normal distribution. /// </summary> /// <param name="x">First upper limit. Must be finite.</param> /// <param name="y">Second upper limit. Must be finite.</param> /// <param name="r">Correlation coefficient.</param> /// <returns><c>phi(x,y,r)</c></returns> /// <remarks> /// The double integral is transformed into a single integral which is approximated by quadrature. /// Reference: /// "Numerical Computation of Rectangular Bivariate and Trivariate Normal and t Probabilities" /// Alan Genz, Statistics and Computing, 14 (2004), pp. 151-160 /// http://www.math.wsu.edu/faculty/genz/genzhome/research.html /// </remarks> private static double NormalCdf_Quadrature(double x, double y, double r) { double absr = System.Math.Abs(r); Vector nodes, weights; int count = 20; if (absr < 0.3) { count = 6; } else if (absr < 0.75) { count = 12; } nodes = Vector.Zero(count); weights = Vector.Zero(count); double result = 0.0; if (absr < 0.925) { // use equation (3) double asinr = System.Math.Asin(r); Quadrature.UniformNodesAndWeights(0, asinr, nodes, weights); double sq = 0.5 * (x * x + y * y), xy = x * y; for (int i = 0; i < nodes.Count; i++) { double sin = System.Math.Sin(nodes[i]); double cos2 = 1 - sin * sin; result += weights[i] * System.Math.Exp((xy * sin - sq) / cos2); } result /= 2 * System.Math.PI; result += MMath.NormalCdf(x, y, 0); } else { double sy = (r < 0) ? -y : y; if (absr < 1) { // use equation (6) modified by (7) // quadrature part double cos2asinr = (1 - r) * (1 + r), sqrt1mrr = System.Math.Sqrt(cos2asinr); Quadrature.UniformNodesAndWeights(0, sqrt1mrr, nodes, weights); double sxy = x * sy; double diff2 = (x - sy) * (x - sy); double c = (4 - sxy) / 8, d = (12 - sxy) / 16; for (int i = 0; i < nodes.Count; i++) { double cos2 = nodes[i] * nodes[i]; double sin = System.Math.Sqrt(1 - cos2); double series = 1 + c * cos2 * (1 + d * cos2); double exponent = -0.5 * (diff2 / cos2 + sxy); double f = System.Math.Exp(-0.5 * sxy * (1 - sin) / (1 + sin)) / sin; result += weights[i] * System.Math.Exp(exponent) * (f - series); } // Taylor expansion part double exponentr = -0.5 * (diff2 / cos2asinr + sxy); double absdiff = System.Math.Sqrt(diff2); if (exponentr > -800) { // avoid 0*Inf problems result += sqrt1mrr * System.Math.Exp(exponentr) * (1 - c * (diff2 - cos2asinr) * (1 - d * diff2 / 5) / 3 + c * d * cos2asinr * cos2asinr / 5); // for large absdiff, NormalCdfLn(-absdiff / sqrt1mrr) =approx -0.5*diff2/cos2asinr // so (-0.5*sxy + NormalCdfLn) =approx exponentr result -= System.Math.Exp(-0.5 * sxy + MMath.NormalCdfLn(-absdiff / sqrt1mrr)) * absdiff * (1 - c * diff2 * (1 - d * diff2 / 5) / 3) * MMath.Sqrt2PI; } result /= -2 * System.Math.PI; } if (r > 0) { // exact value for r=1 result += MMath.NormalCdf(x, y, 1); } else { // exact value for r=-1 result = -result; result += MMath.NormalCdf(x, y, -1); } } if (result < 0) { result = 0.0; } else if (result > 1) { result = 1.0; } return(result); }
// Used to debug MMath.NormalCdf internal void NormalCdf2Test3() { double x, y, r; bool first = true; if (first) { // x=-2, y=-10, r=0.9 is dominated by additive part of numerator - poor convergence // -2,-2,-0.5 x = -1.0058535005109381; y = -0.11890687017604007; r = -0.79846947062734286; x = -63; y = 63; r = -0.4637494637494638; x = -1.0329769464004883E-08; y = 1.0329769464004876E-08; r = -0.99999999999999512; x = 0; y = 0; r = -0.6; x = -1.15950886531361; y = 0.989626418003324; r = -0.626095038754337; x = -1.5; y = 1.5; r = -0.49; x = -1.6450031341281908; y = 1.2645625117080999; r = -0.054054238344620031; x = -0.5; y = -0.5; r = 0.001; Console.WriteLine(1 - r * r); Console.WriteLine("NormalCdfBrute: {0}", NormalCdfBrute(0, x, y, r)); Console.WriteLine("NormalCdf_Quadrature: {0}", NormalCdf_Quadrature(x, y, r)); //Console.WriteLine("{0}", NormalCdfAlt2(x, y, r)); //Console.WriteLine("NormalCdfAlt: {0}", NormalCdfAlt(x, y, r)); //Console.WriteLine("NormalCdfTaylor: {0}", MMath.NormalCdfRatioTaylor(x, y, r)); //Console.WriteLine("NormalCdfConFrac3: {0}", NormalCdfConFrac3(x, y, r)); //Console.WriteLine("NormalCdfConFrac4: {0}", NormalCdfConFrac4(x, y, r)); //Console.WriteLine("NormalCdfConFrac5: {0}", NormalCdfConFrac5(x, y, r)); Console.WriteLine("MMath.NormalCdf: {0}", MMath.NormalCdf(x, y, r)); Console.WriteLine("MMath.NormalCdfLn: {0}", MMath.NormalCdfLn(x, y, r)); for (int i = 1; i < 50; i++) { //Console.WriteLine("{0}: {1}", i, NormalCdfBrute(i, x, y, r)); } //x = 0; //y = 0; //r2 = -0.7; //r2 = -0.999; } else { // x=-2, y=-10, r=0.9 is dominated by additive part of numerator - poor convergence // -2,-2,-0.5 x = -0.1; y = -0.1; r = -0.999999; Console.WriteLine("{0}", MMath.NormalCdfLn(x, y, r)); //x = 0; //y = 0; //r2 = -0.7; //r2 = -0.999; } }
private double NormalCdfIntegralFlip(double x, double y, double r) { double logProbX = Gaussian.GetLogProb(x, 0, 1); return(-MMath.NormalCdfIntegral(x, -y, -r) + x * MMath.NormalCdf(x) + System.Math.Exp(logProbX)); }