double lgamma_r (double x, int *signp) { *signp = +1; if (gnm_isnan (x)) return gnm_nan; if (x > 0) { gnm_float f = 1; while (x < 10) { f *= x; x++; } return (M_LN_SQRT_2PI + (x - 0.5) * gnm_log(x) - x + lgammacor(x)) - gnm_log (f); } else { gnm_float axm2 = gnm_fmod (-x, 2.0); gnm_float y = gnm_sinpi (axm2) / M_PIgnum; *signp = axm2 > 1.0 ? +1 : -1; return y == 0 ? gnm_nan : - gnm_log (gnm_abs (y)) - lgamma1p (-x); } }
static gnm_float lgammacor(gnm_float x) { static const gnm_float algmcs[15] = { GNM_const(+.1666389480451863247205729650822e+0), GNM_const(-.1384948176067563840732986059135e-4), GNM_const(+.9810825646924729426157171547487e-8), GNM_const(-.1809129475572494194263306266719e-10), GNM_const(+.6221098041892605227126015543416e-13), GNM_const(-.3399615005417721944303330599666e-15), GNM_const(+.2683181998482698748957538846666e-17), GNM_const(-.2868042435334643284144622399999e-19), GNM_const(+.3962837061046434803679306666666e-21), GNM_const(-.6831888753985766870111999999999e-23), GNM_const(+.1429227355942498147573333333333e-24), GNM_const(-.3547598158101070547199999999999e-26), GNM_const(+.1025680058010470912000000000000e-27), GNM_const(-.3401102254316748799999999999999e-29), GNM_const(+.1276642195630062933333333333333e-30) }; gnm_float tmp; #ifdef NOMORE_FOR_THREADS static int nalgm = 0; static gnm_float xbig = 0, xmax = 0; /* Initialize machine dependent constants, the first time gamma() is called. FIXME for threads ! */ if (nalgm == 0) { /* For IEEE gnm_float precision : nalgm = 5 */ nalgm = chebyshev_init(algmcs, 15, GNM_EPSILON/2);/*was d1mach(3)*/ xbig = 1 / gnm_sqrt(GNM_EPSILON/2); /* ~ 94906265.6 for IEEE gnm_float */ xmax = gnm_exp(fmin2(gnm_log(GNM_MAX / 12), -gnm_log(12 * GNM_MIN))); /* = GNM_MAX / 48 ~= 3.745e306 for IEEE gnm_float */ } #else /* For IEEE gnm_float precision GNM_EPSILON = 2^-52 = GNM_const(2.220446049250313e-16) : * xbig = 2 ^ 26.5 * xmax = GNM_MAX / 48 = 2^1020 / 3 */ # define nalgm 5 # define xbig GNM_const(94906265.62425156) # define xmax GNM_const(3.745194030963158e306) #endif if (x < 10) ML_ERR_return_NAN else if (x >= xmax) { ML_ERROR(ME_UNDERFLOW); return ML_UNDERFLOW; } else if (x < xbig) { tmp = 10 / x; return chebyshev_eval(tmp * tmp * 2 - 1, algmcs, nalgm) / x; } else return 1 / (x * 12); }
gnm_float stirlerr(gnm_float n) { #define S0 GNM_const(0.083333333333333333333) /* 1/12 */ #define S1 GNM_const(0.00277777777777777777778) /* 1/360 */ #define S2 GNM_const(0.00079365079365079365079365) /* 1/1260 */ #define S3 GNM_const(0.000595238095238095238095238) /* 1/1680 */ #define S4 GNM_const(0.0008417508417508417508417508)/* 1/1188 */ /* error for 0, 0.5, 1.0, 1.5, ..., 14.5, 15.0. */ static const gnm_float sferr_halves[31] = { 0.0, /* n=0 - wrong, place holder only */ GNM_const(0.1534264097200273452913848), /* 0.5 */ GNM_const(0.0810614667953272582196702), /* 1.0 */ GNM_const(0.0548141210519176538961390), /* 1.5 */ GNM_const(0.0413406959554092940938221), /* 2.0 */ GNM_const(0.03316287351993628748511048), /* 2.5 */ GNM_const(0.02767792568499833914878929), /* 3.0 */ GNM_const(0.02374616365629749597132920), /* 3.5 */ GNM_const(0.02079067210376509311152277), /* 4.0 */ GNM_const(0.01848845053267318523077934), /* 4.5 */ GNM_const(0.01664469118982119216319487), /* 5.0 */ GNM_const(0.01513497322191737887351255), /* 5.5 */ GNM_const(0.01387612882307074799874573), /* 6.0 */ GNM_const(0.01281046524292022692424986), /* 6.5 */ GNM_const(0.01189670994589177009505572), /* 7.0 */ GNM_const(0.01110455975820691732662991), /* 7.5 */ GNM_const(0.010411265261972096497478567), /* 8.0 */ GNM_const(0.009799416126158803298389475), /* 8.5 */ GNM_const(0.009255462182712732917728637), /* 9.0 */ GNM_const(0.008768700134139385462952823), /* 9.5 */ GNM_const(0.008330563433362871256469318), /* 10.0 */ GNM_const(0.007934114564314020547248100), /* 10.5 */ GNM_const(0.007573675487951840794972024), /* 11.0 */ GNM_const(0.007244554301320383179543912), /* 11.5 */ GNM_const(0.006942840107209529865664152), /* 12.0 */ GNM_const(0.006665247032707682442354394), /* 12.5 */ GNM_const(0.006408994188004207068439631), /* 13.0 */ GNM_const(0.006171712263039457647532867), /* 13.5 */ GNM_const(0.005951370112758847735624416), /* 14.0 */ GNM_const(0.005746216513010115682023589), /* 14.5 */ GNM_const(0.005554733551962801371038690) /* 15.0 */ }; gnm_float nn; if (n <= 15.0) { nn = n + n; if (nn == (int)nn) return(sferr_halves[(int)nn]); return(lgamma1p (n ) - (n + 0.5)*gnm_log(n) + n - M_LN_SQRT_2PI); } nn = n*n; if (n>500) return((S0-S1/nn)/n); if (n> 80) return((S0-(S1-S2/nn)/nn)/n); if (n> 35) return((S0-(S1-(S2-S3/nn)/nn)/nn)/n); /* 15 < n <= 35 : */ return((S0-(S1-(S2-(S3-S4/nn)/nn)/nn)/nn)/n); }
gnm_float dsnorm (gnm_float x, gnm_float shape, gnm_float location, gnm_float scale, gboolean give_log) { if (shape == 0.) return dnorm (x, location, scale, give_log); else if (give_log) return gnm_log (2.) + dnorm (x, location, scale, TRUE) + pnorm (shape * x, shape * location, scale, TRUE, TRUE); else return 2 * dnorm (x, location, scale, FALSE) * pnorm (shape * x, location/shape, scale, TRUE, FALSE); }
void gsl_complex_arccos (complex_t const *a, complex_t *res) { /* z = arccos(a) */ gnm_float R = GSL_REAL (a), I = GSL_IMAG (a); if (I == 0) { gsl_complex_arccos_real (R, res); } else { gnm_float x = gnm_abs (R); gnm_float y = gnm_abs (I); gnm_float r = gnm_hypot (x + 1, y); gnm_float s = gnm_hypot (x - 1, y); gnm_float A = 0.5 * (r + s); gnm_float B = x / A; gnm_float y2 = y * y; gnm_float real, imag; const gnm_float A_crossover = 1.5; const gnm_float B_crossover = 0.6417; if (B <= B_crossover) { real = gnm_acos (B); } else { if (x <= 1) { gnm_float D = 0.5 * (A + x) * (y2 / (r + x + 1) + (s + (1 - x))); real = gnm_atan (gnm_sqrt (D) / x); } else { gnm_float Apx = A + x; gnm_float D = 0.5 * (Apx / (r + x + 1) + Apx / (s + (x - 1))); real = gnm_atan ((y * gnm_sqrt (D)) / x); } } if (A <= A_crossover) { gnm_float Am1; if (x < 1) { Am1 = 0.5 * (y2 / (r + (x + 1)) + y2 / (s + (1 - x))); } else { Am1 = 0.5 * (y2 / (r + (x + 1)) + (s + (x - 1))); } imag = gnm_log1p (Am1 + gnm_sqrt (Am1 * (A + 1))); } else { imag = gnm_log (A + gnm_sqrt (A * A - 1)); } complex_init (res, (R >= 0) ? real : M_PIgnum - real, (I >= 0) ? -imag : imag); } }
gnm_float dst (gnm_float x, gnm_float n, gnm_float shape, gboolean give_log) { if (shape == 0.) return dt (x, n, give_log); else { gnm_float pdf = dt (x, n, give_log); gnm_float cdf = pt (shape * x * gnm_sqrt ((n + 1)/(x * x + n)), n + 1, TRUE, give_log); return ((give_log) ? (gnm_log (2.) + pdf + cdf) : (2. * pdf * cdf)); } }
gnm_float qgumbel (gnm_float p, gnm_float mu, gnm_float beta, gboolean lower_tail, gboolean log_p) { if (!(beta > 0) || gnm_isnan (mu) || gnm_isnan (beta) || gnm_isnan (p) || (log_p ? p > 0 : (p < 0 || p > 1))) return gnm_nan; if (log_p) { if (!lower_tail) p = swap_log_tail (p); } else { if (lower_tail) p = gnm_log (p); else p = gnm_log1p (-p); } /* We're now in the log_p, lower_tail case. */ return mu - beta * gnm_log (-p); }
gnm_float dgumbel (gnm_float x, gnm_float mu, gnm_float beta, gboolean give_log) { gnm_float z, lp; if (!(beta > 0) || gnm_isnan (mu) || gnm_isnan (beta) || gnm_isnan (x)) return gnm_nan; z = (x - mu) / beta; lp = -(z + gnm_exp (-z)); return give_log ? lp - gnm_log (beta) : gnm_exp (lp) / beta; }
gnm_float gnm_lbeta(gnm_float a, gnm_float b) { gnm_float corr, p, q; p = q = a; if(b < p) p = b;/* := min(a,b) */ if(b > q) q = b;/* := max(a,b) */ #ifdef IEEE_754 if(gnm_isnan(a) || gnm_isnan(b)) return a + b; #endif /* both arguments must be >= 0 */ if (p < 0) ML_ERR_return_NAN else if (p == 0) { return gnm_pinf; } else if (!gnm_finite(q)) { return gnm_ninf; } if (p >= 10) { /* p and q are big. */ corr = lgammacor(p) + lgammacor(q) - lgammacor(p + q); return gnm_log(q) * -0.5 + M_LN_SQRT_2PI + corr + (p - 0.5) * gnm_log(p / (p + q)) + q * gnm_log1p(-p / (p + q)); } else if (q >= 10) { /* p is small, but q is big. */ corr = lgammacor(q) - lgammacor(p + q); return gnm_lgamma(p) + corr + p - p * gnm_log(p + q) + (q - 0.5) * gnm_log1p(-p / (p + q)); } else /* p and q are small: p <= q < 10. */ return gnm_lgamma (p) + gnm_lgamma (q) - gnm_lgamma (p + q); }
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; }
gnm_float psnorm (gnm_float x, gnm_float shape, gnm_float location, gnm_float scale, gboolean lower_tail, gboolean log_p) { gnm_float result; if (shape == 0.) return pnorm (x, location, scale, lower_tail, log_p); result = pnorm (x, location, scale, TRUE, FALSE) - 2 * gnm_owent ((x - location)/scale, shape); if (!lower_tail) result = 1. - result; if (log_p) return gnm_log (result); else return result; }
void gsl_complex_arctan (complex_t const *a, complex_t *res) { /* z = arctan(a) */ gnm_float R = GSL_REAL (a), I = GSL_IMAG (a); if (I == 0) { complex_init (res, gnm_atan (R), 0); } else { /* FIXME: This is a naive implementation which does not fully * take into account cancellation errors, overflow, underflow * etc. It would benefit from the Hull et al treatment. */ gnm_float r = gnm_hypot (R, I); gnm_float imag; gnm_float u = 2 * I / (1 + r * r); /* FIXME: the following cross-over should be optimized but 0.1 * seems to work ok */ if (gnm_abs (u) < 0.1) { imag = 0.25 * (gnm_log1p (u) - gnm_log1p (-u)); } else { gnm_float A = gnm_hypot (R, I + 1); gnm_float B = gnm_hypot (R, I - 1); imag = 0.5 * gnm_log (A / B); } if (R == 0) { if (I > 1) { complex_init (res, M_PI_2gnum, imag); } else if (I < -1) { complex_init (res, -M_PI_2gnum, imag); } else { complex_init (res, 0, imag); } } else { complex_init (res, 0.5 * gnm_atan2 (2 * R, ((1 + r) * (1 - r))), imag); } } }
/** * gnm_lbeta3: * @a: a number * @b: a number * @sign: (out): the sign * * Returns: the logarithm of the absolute value of the Beta function * evaluated at @a and @b. The sign will be stored in @sign as -1 or * +1. This function is useful because the result of the beta * function can be too large for doubles. */ gnm_float gnm_lbeta3 (gnm_float a, gnm_float b, int *sign) { int sign_a, sign_b, sign_ab; gnm_float ab = a + b; gnm_float res_a, res_b, res_ab; GnmQuad r; int e; switch (qbetaf (a, b, &r, &e)) { case 0: { gnm_float m = gnm_quad_value (&r); *sign = (m >= 0 ? +1 : -1); return gnm_log (gnm_abs (m)) + e * M_LN2gnum; } case 1: /* Overflow */ break; default: *sign = 1; return gnm_nan; } if (a > 0 && b > 0) { *sign = 1; return gnm_lbeta (a, b); } /* This is awful */ res_a = gnm_lgamma_r (a, &sign_a); res_b = gnm_lgamma_r (b, &sign_b); res_ab = gnm_lgamma_r (ab, &sign_ab); *sign = sign_a * sign_b * sign_ab; return res_a + res_b - res_ab; }
gnm_float pochhammer (gnm_float x, gnm_float n) { gnm_float rn, rx, lr; GnmQuad m1, m2; int e1, e2; if (gnm_isnan (x) || gnm_isnan (n)) return gnm_nan; if (n == 0) return 1; rx = gnm_floor (x); rn = gnm_floor (n); /* * Use naive multiplication when n is a small integer. * We don't want to use this if x is also an integer * (but we might do so below if x is insanely large). */ if (n == rn && x != rx && n >= 0 && n < 40) return pochhammer_naive (x, (int)n); if (!qfactf (x + n - 1, &m1, &e1) && !qfactf (x - 1, &m2, &e2)) { void *state = gnm_quad_start (); int de = e1 - e2; GnmQuad qr; gnm_float r; gnm_quad_div (&qr, &m1, &m2); r = gnm_quad_value (&qr); gnm_quad_end (state); return gnm_ldexp (r, de); } if (x == rx && x <= 0) { if (n != rn) return 0; if (x == 0) return (n > 0) ? 0 : ((gnm_fmod (-n, 2) == 0 ? +1 : -1) / gnm_fact (-n)); if (n > -x) return gnm_nan; } /* * We have left the common cases. One of x+n and x is * insanely big, possibly both. */ if (gnm_abs (x) < 1) return gnm_pinf; if (n < 0) return 1 / pochhammer (x + n, -n); if (n == rn && n >= 0 && n < 100) return pochhammer_naive (x, (int)n); if (gnm_abs (n) < 1) { /* x is big. */ void *state = gnm_quad_start (); GnmQuad qr; gnm_float r; pochhammer_small_n (x, n, &qr); r = gnm_quad_value (&qr); gnm_quad_end (state); return r; } /* Panic mode. */ g_printerr ("x=%.20g n=%.20g\n", x, n); lr = ((x - 0.5) * gnm_log1p (n / x) + n * gnm_log (x + n) - n + (lgammacor (x + n) - lgammacor (x))); return gnm_exp (lr); }
gnm_float pst (gnm_float x, gnm_float n, gnm_float shape, gboolean lower_tail, gboolean log_p) { gnm_float p; if (n <= 0 || gnm_isnan (x) || gnm_isnan (n) || gnm_isnan (shape)) return gnm_nan; if (shape == 0.) return pt (x, n, lower_tail, log_p); if (n > 100) { /* Approximation */ return psnorm (x, shape, 0.0, 1.0, lower_tail, log_p); } /* Flip to a lower-tail problem. */ if (!lower_tail) { x = -x; shape = -shape; lower_tail = !lower_tail; } /* Generic fallback. */ if (log_p) gnm_log (pst (x, n, shape, TRUE, FALSE)); if (n != gnm_floor (n)) { /* We would need numerical integration for this. */ return gnm_nan; } /* * Use recurrence formula from "Recurrent relations for * distributions of a skew-t and a linear combination of order * statistics form a bivariate-t", Computational Statistics * and Data Analysis volume 52, 2009 by Jamallizadeh, * Khosravi, Balakrishnan. * * This brings us down to n==1 or n==2 for which explicit formulas * are available. */ p = 0; while (n > 2) { double a, lb, c, d, pv, v = n - 1; d = v == 2 ? M_LN2gnum - gnm_log (M_PIgnum) + gnm_log (3) / 2 : (0.5 + M_LN2gnum / 2 - gnm_log (M_PIgnum) / 2 + v / 2 * (gnm_log1p (-1 / (v - 1)) + gnm_log (v + 1)) - 0.5 * (gnm_log (v - 2) + gnm_log (v + 1)) + stirlerr (v / 2 - 1) - stirlerr ((v - 1) / 2)); a = v + 1 + x * x; lb = (d - gnm_log (a) * v / 2); c = pt (gnm_sqrt (v) * shape * x / gnm_sqrt (a), v, TRUE, FALSE); pv = x * gnm_exp (lb) * c; p += pv; n -= 2; x *= gnm_sqrt ((v - 1) / (v + 1)); } g_return_val_if_fail (n == 1 || n == 2, gnm_nan); if (n == 1) { gnm_float p1; p1 = (gnm_atan (x) + gnm_acos (shape / gnm_sqrt ((1 + shape * shape) * (1 + x * x)))) / M_PIgnum; p += p1; } else if (n == 2) { gnm_float p2, f; f = x / gnm_sqrt (2 + x * x); p2 = (gnm_atan_mpihalf (shape) + f * gnm_atan_mpihalf (-shape * f)) / -M_PIgnum; p += p2; } else { return gnm_nan; } /* * Negatives can occur due to rounding errors and hopefully for no * other reason. */ p = CLAMP (p, 0.0, 1.0); return p; }
/** * FIXME: In the long term this needs optimising. **/ static GnmValue * val_to_base (GnmFuncEvalInfo *ei, GnmValue const *value, GnmValue const *aplaces, int src_base, int dest_base, gnm_float min_value, gnm_float max_value, Val2BaseFlags flags) { int digit, min, max, places; gnm_float v; GString *buffer; GnmValue *vstring = NULL; g_return_val_if_fail (src_base > 1 && src_base <= 36, value_new_error_VALUE (ei->pos)); g_return_val_if_fail (dest_base > 1 && dest_base <= 36, value_new_error_VALUE (ei->pos)); /* func.c ought to take care of this. */ if (VALUE_IS_BOOLEAN (value)) return value_new_error_VALUE (ei->pos); if (aplaces && VALUE_IS_BOOLEAN (aplaces)) return value_new_error_VALUE (ei->pos); switch (value->type) { default: return value_new_error_NUM (ei->pos); case VALUE_STRING: if (flags & V2B_STRINGS_GENERAL) { vstring = format_match_number (value_peek_string (value), NULL, workbook_date_conv (ei->pos->sheet->workbook)); if (!vstring || !VALUE_IS_FLOAT (vstring)) { value_release (vstring); return value_new_error_VALUE (ei->pos); } } else { char const *str = value_peek_string (value); size_t len; gboolean hsuffix = FALSE; char *err; if ((flags & V2B_STRINGS_BLANK_ZERO) && *str == 0) str = "0"; /* This prevents leading spaces, signs, etc, and "". */ if (!g_ascii_isalnum (*str)) return value_new_error_NUM (ei->pos); len = strlen (str); /* We check length in bytes. Since we are going to require nothing but digits, that is fine. */ if ((flags & V2B_STRINGS_MAXLEN) && len > 10) return value_new_error_NUM (ei->pos); if (flags & V2B_STRINGS_0XH) { if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) str += 2; else if (str[len - 1] == 'h' || str[len - 1] == 'H') hsuffix = TRUE; } v = g_ascii_strtoll (str, &err, src_base); if (err == str || err[hsuffix] != 0) return value_new_error_NUM (ei->pos); if (v < min_value || v > max_value) return value_new_error_NUM (ei->pos); break; } /* Fall through. */ case VALUE_FLOAT: { gnm_float val = gnm_fake_trunc (value_get_as_float (vstring ? vstring : value)); char buf[GNM_MANT_DIG + 10]; char *err; value_release (vstring); if (val < min_value || val > max_value) return value_new_error_NUM (ei->pos); g_ascii_formatd (buf, sizeof (buf) - 1, "%.0" GNM_FORMAT_f, val); v = g_ascii_strtoll (buf, &err, src_base); if (*err != 0) return value_new_error_NUM (ei->pos); break; } } if (src_base != 10) { gnm_float b10 = gnm_pow (src_base, 10); if (v >= b10 / 2) /* N's complement */ v = v - b10; } if (flags & V2B_NUMBER) return value_new_float (v); if (v < 0) { min = 1; max = 10; v += gnm_pow (dest_base, max); } else { if (v == 0) min = max = 1; else min = max = (int)(gnm_log (v + 0.5) / gnm_log (dest_base)) + 1; } if (aplaces) { gnm_float fplaces = value_get_as_float (aplaces); if (fplaces < min || fplaces > 10) return value_new_error_NUM (ei->pos); places = (int)fplaces; if (v >= 0 && places > max) max = places; } else places = 1; buffer = g_string_sized_new (max); g_string_set_size (buffer, max); for (digit = max - 1; digit >= 0; digit--) { int thisdigit = gnm_fmod (v + 0.5, dest_base); v = gnm_floor ((v + 0.5) / dest_base); buffer->str[digit] = thisdigit["0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"]; } return value_new_string_nocopy (g_string_free (buffer, FALSE)); }