static GnmValue * gnumeric_erf (GnmFuncEvalInfo *ei, GnmValue const * const *argv) { gnm_float lower = value_get_as_float (argv[0]); gnm_float ans; if (argv[1]) { gnm_float upper = value_get_as_float (argv[1]); ans = 2 * pnorm2 (lower * M_SQRT2gnum, upper * M_SQRT2gnum); } else ans = gnm_erf (lower); return value_new_float (ans); }
gnm_float psnorm (gnm_float x, gnm_float shape, gnm_float location, gnm_float scale, gboolean lower_tail, gboolean log_p) { gnm_float result, h; if (gnm_isnan (x) || gnm_isnan (shape) || gnm_isnan (location) || gnm_isnan (scale)) return gnm_nan; if (shape == 0.) return pnorm (x, location, scale, lower_tail, log_p); /* Normalize */ h = (x - location) / scale; /* Flip to a lower-tail problem. */ if (!lower_tail) { h = -h; shape = -shape; lower_tail = !lower_tail; } if (gnm_abs (shape) < 10) { gnm_float s = pnorm (h, 0, 1, lower_tail, FALSE); gnm_float t = 2 * gnm_owent (h, shape); result = s - t; } else { /* * Make use of this result for Owen's T: * * T(h,a) = .5N(h) + .5N(ha) - N(h)N(ha) - T(ha,1/a) */ gnm_float s = pnorm (h * shape, 0, 1, TRUE, FALSE); gnm_float u = gnm_erf (h / M_SQRT2gnum); gnm_float t = 2 * gnm_owent (h * shape, 1 / shape); result = s * u + t; } /* * Negatives can occur due to rounding errors and hopefully for no * other reason. */ result= CLAMP (result, 0.0, 1.0); if (log_p) return gnm_log (result); else return result; }