public void NormalCdfIntegralTest() { Assert.True(0 <= NormalCdfIntegral(190187183095334850882507750944849586799124505055478568794871547478488387682304.0, -190187183095334850882507750944849586799124505055478568794871547478488387682304.0, -1, 0.817880416082724044547388352452631856079457366800004151664125953519049673808376291470533145141236089924006896061006277409614237094627499958581030715374379576478204968748786874650796450332240045653919846557755590765736997127532958984375e-78).Mantissa); Assert.True(0 <= NormalCdfIntegral(213393529.2046706974506378173828125, -213393529.2046706974506378173828125, -1, 0.72893668811495072384656764856902984306419313043079455383121967315673828125e-9).Mantissa); Assert.True(0 < NormalCdfIntegral(-0.421468532207607216033551367218024097383022308349609375, 0.42146843802130329326161017888807691633701324462890625, -0.99999999999999989, 0.62292398855983019004972723654291189010479001808562316000461578369140625e-8).Mantissa); // Checking all cases takes a long time. const int limit = 2_000_000; int count = 0; Parallel.ForEach(OperatorTests.Doubles(), x => { if (count > limit) { return; } foreach (var y in OperatorTests.Doubles()) { if (count > limit) { break; } foreach (var r in OperatorTests.Doubles().Where(d => d >= -1 && d <= 1)) { if (count > limit) { break; } MMath.NormalCdfIntegral(x, y, r); Interlocked.Add(ref count, 1); } } }); }
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); }
// Same as MMath.NormalCdfIntegral but avoids inconsistent values of r and sqrtomr2 when using arbitrary precision. public static ExtendedDouble NormalCdfIntegral(double x, double y, double r, double sqrtomr2) { if (sqrtomr2 < 0.618) { // In this regime, it is more accurate to compute r from sqrtomr2. // See NormalCdfRatioLn r = System.Math.Sign(r) * System.Math.Sqrt((1 - sqrtomr2) * (1 + sqrtomr2)); } else { // In this regime, it is more accurate to compute sqrtomr2 from r. double omr2 = 1 - r * r; sqrtomr2 = System.Math.Sqrt(omr2); } return(MMath.NormalCdfIntegral(x, y, r, sqrtomr2)); }
/// <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}"); } } } } }
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)); }
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(); } } }