public static double inv_m1_approx_smart(double beta, double f, double sigma) { // Compute some relevant bounds var log_001 = -4.605170186; var lo = log_001 * (1 - beta) - 0.5 * sigma * sigma; var hi = Math.Min(37 - 0.5 * sigma * sigma, 0.5 * sigma * sigma); //! < 10 // Evaluate the function on those points // Using the actual function to too costly var zz = 0.0; var vlo = m1_beta_black(beta, lo, sigma); var dhi_dmu = 0.0; var vhi = m1_beta_black_b(beta, hi, sigma, ref zz, ref dhi_dmu, ref zz, 1.0); // Treat bounds if (f < vlo) { return(inv_g(beta, f)); // no convexity } if (f > vhi) { return(inv_g(beta, f) - 0.5 * sigma * sigma); // full convexity } //! Middle region, fit approximately // a + b x + c exp(d x) var d = dhi_dmu / vhi; var c = vhi / Math.Exp(dhi_dmu * hi / vhi); var b = -(vlo - c * Math.Exp(d * lo)) / (hi - lo); var a = -b * hi; //! The invert in closed form var aw = Math.Exp(-d * (a - f) / b) * c * d / b; return(-(b * SpecialFunction.wapr(aw) + a * d - d * f) / (b * d)); }
public static double inv_g(double beta, double y) { if (beta == 0.0 || y >= 1.0) { return(Math.Log(y)); } var expo = -(beta * beta - 2.0 * beta + y) / (beta * (beta - 1.0)); if (expo > 700.0) { //! This happens only for small beta //! Need solution here - default to newton iteration? //! For the time being we use an expansion var l1 = expo + Math.Log((1 - beta) / beta); // no risk here, beta is small var l12 = l1 * l1; var l13 = l12 * l1; var l14 = l12 * l12; var l15 = l14 * l12; var l2 = Math.Log(l1); var l22 = l2 * l2; var l23 = l22 * l2; var l24 = l23 * l2; var wwb = l1 - l2 + l2 / l1 + l2 * (-2.0 + l2) / (2.0 * l12) + l2 * (6.0 - 9.0 * l2 + 2.0 * l22) / (6.0 * l13) + l2 * (-12.0 + 36.0 * l2 - 22.0 * l22 + 3.0 * l23) / (12.0 * l14) + l2 * (60.0 - 300.0 * l2 + 350.0 * l22 - 125.0 * l23 + 12.0 * l24) / (60.0 * l15); return(beta * wwb - wwb + beta - 2.0 + y / beta); } var aw = Math.Exp(expo) * (1.0 - beta) / beta; var wb = SpecialFunction.wapr(aw); return(beta * wb - wb + beta - 2.0 + y / beta); }
public static double inv_m1_beta_black_approx_2(double beta, double f, double sigma) { //! Numerical var expArg = -1.0 * (SpecialFunction.pow2(beta) - 2.0 * beta + f) / ((-1.0 + beta) * beta); if (expArg > 37.0) { return(inv_g(beta, f)); } var aw = -0.5000000000 * (2.0 * SpecialFunction.pow2(beta) + SpecialFunction.pow2(sigma) - 4.0 * beta + 2.0) * Math.Exp(expArg) / ((-1.0 + beta) * beta); var wb = SpecialFunction.wapr(aw); return(beta * wb - wb + beta - 2.0 + f / beta); }