comparison Modules/mathmodule.c @ 57655:cb22eaee86c9 legacy-trunk

Issue #3366: Add lgamma function to math module.
author Mark Dickinson <dickinsm@gmail.com>
date Fri, 11 Dec 2009 17:29:33 +0000
parents 7e02371aa506
children b206ad8cf5bf
comparison
equal deleted inserted replaced
57650:ae9396260835 57655:cb22eaee86c9
318 } 318 }
319 if (Py_IS_INFINITY(r)) 319 if (Py_IS_INFINITY(r))
320 errno = ERANGE; 320 errno = ERANGE;
321 return r; 321 return r;
322 } 322 }
323
324 /*
325 lgamma: natural log of the absolute value of the Gamma function.
326 For large arguments, Lanczos' formula works extremely well here.
327 */
328
329 static double
330 m_lgamma(double x)
331 {
332 double r, absx;
333
334 /* special cases */
335 if (!Py_IS_FINITE(x)) {
336 if (Py_IS_NAN(x))
337 return x; /* lgamma(nan) = nan */
338 else
339 return Py_HUGE_VAL; /* lgamma(+-inf) = +inf */
340 }
341
342 /* integer arguments */
343 if (x == floor(x) && x <= 2.0) {
344 if (x <= 0.0) {
345 errno = EDOM; /* lgamma(n) = inf, divide-by-zero for */
346 return Py_HUGE_VAL; /* integers n <= 0 */
347 }
348 else {
349 return 0.0; /* lgamma(1) = lgamma(2) = 0.0 */
350 }
351 }
352
353 absx = fabs(x);
354 /* tiny arguments: lgamma(x) ~ -log(fabs(x)) for small x */
355 if (absx < 1e-20)
356 return -log(absx);
357
358 /* Lanczos' formula */
359 if (x > 0.0) {
360 /* we could save a fraction of a ulp in accuracy by having a
361 second set of numerator coefficients for lanczos_sum that
362 absorbed the exp(-lanczos_g) term, and throwing out the
363 lanczos_g subtraction below; it's probably not worth it. */
364 r = log(lanczos_sum(x)) - lanczos_g +
365 (x-0.5)*(log(x+lanczos_g-0.5)-1);
366 }
367 else {
368 r = log(pi) - log(fabs(sinpi(absx))) - log(absx) -
369 (log(lanczos_sum(absx)) - lanczos_g +
370 (absx-0.5)*(log(absx+lanczos_g-0.5)-1));
371 }
372 if (Py_IS_INFINITY(r))
373 errno = ERANGE;
374 return r;
375 }
376
323 377
324 /* 378 /*
325 wrapper for atan2 that deals directly with special cases before 379 wrapper for atan2 that deals directly with special cases before
326 delegating to the platform libm for the remaining cases. This 380 delegating to the platform libm for the remaining cases. This
327 is necessary to get consistent behaviour across platforms. 381 is necessary to get consistent behaviour across platforms.
637 FUNC1(floor, floor, 0, 691 FUNC1(floor, floor, 0,
638 "floor(x)\n\nReturn the floor of x as a float.\n" 692 "floor(x)\n\nReturn the floor of x as a float.\n"
639 "This is the largest integral value <= x.") 693 "This is the largest integral value <= x.")
640 FUNC1A(gamma, m_tgamma, 694 FUNC1A(gamma, m_tgamma,
641 "gamma(x)\n\nGamma function at x.") 695 "gamma(x)\n\nGamma function at x.")
696 FUNC1A(lgamma, m_lgamma,
697 "lgamma(x)\n\nNatural logarithm of absolute value of Gamma function at x.")
642 FUNC1(log1p, log1p, 1, 698 FUNC1(log1p, log1p, 1,
643 "log1p(x)\n\nReturn the natural logarithm of 1+x (base e).\n" 699 "log1p(x)\n\nReturn the natural logarithm of 1+x (base e).\n"
644 "The result is computed in a way which is accurate for x near zero.") 700 "The result is computed in a way which is accurate for x near zero.")
645 FUNC1(sin, sin, 0, 701 FUNC1(sin, sin, 0,
646 "sin(x)\n\nReturn the sine of x (measured in radians).") 702 "sin(x)\n\nReturn the sine of x (measured in radians).")
1373 {"gamma", math_gamma, METH_O, math_gamma_doc}, 1429 {"gamma", math_gamma, METH_O, math_gamma_doc},
1374 {"hypot", math_hypot, METH_VARARGS, math_hypot_doc}, 1430 {"hypot", math_hypot, METH_VARARGS, math_hypot_doc},
1375 {"isinf", math_isinf, METH_O, math_isinf_doc}, 1431 {"isinf", math_isinf, METH_O, math_isinf_doc},
1376 {"isnan", math_isnan, METH_O, math_isnan_doc}, 1432 {"isnan", math_isnan, METH_O, math_isnan_doc},
1377 {"ldexp", math_ldexp, METH_VARARGS, math_ldexp_doc}, 1433 {"ldexp", math_ldexp, METH_VARARGS, math_ldexp_doc},
1434 {"lgamma", math_lgamma, METH_O, math_lgamma_doc},
1378 {"log", math_log, METH_VARARGS, math_log_doc}, 1435 {"log", math_log, METH_VARARGS, math_log_doc},
1379 {"log1p", math_log1p, METH_O, math_log1p_doc}, 1436 {"log1p", math_log1p, METH_O, math_log1p_doc},
1380 {"log10", math_log10, METH_O, math_log10_doc}, 1437 {"log10", math_log10, METH_O, math_log10_doc},
1381 {"modf", math_modf, METH_O, math_modf_doc}, 1438 {"modf", math_modf, METH_O, math_modf_doc},
1382 {"pow", math_pow, METH_VARARGS, math_pow_doc}, 1439 {"pow", math_pow, METH_VARARGS, math_pow_doc},