cc [ flags ] -I/usr/local/include file(s) -L/usr/local/lib -lmcw [ ... ] #include <mathcw.h> extern float logbfactf (int n, int *pj); extern double logbfact (int n, int *pj); extern long double logbfactl (int n, int *pj); extern __float80 logbfactw (int n, int *pj); extern __float128 logbfactq (int n, int *pj); extern long_long_double logbfactll (int n, int *pj); extern decimal_float logbfactdf (int n, int *pj); extern decimal_double logbfactd (int n, int *pj); extern decimal_long_double logbfactdl (int n, int *pj); extern decimal_long_long_double logbfactdll (int n, int *pj);
NB: Functions with prototypes containing underscores in type names may be available only with certain extended compilers.
The result is the sum of an integer and a fraction in [-1/2,1/2], such that the sum represents the logarithm to a few extra digits of precision.
This function makes it possible to compute expressions containing factorials without premature underflow and overflow, and without resorting to the exponential (exp(3CW)) and log-gamma (lgamma(3CW)) functions. That approach introduces large mathematically-unavoidable errors in the computed result when the argument of the exponential is large, because the error magnification of that function is proportional to its argument.
For example, to compute the product x**(-a) * n!, where ** is the power operaor, decompose the expression like this:
The expbeta() function here is to be replaced by a base-specific function, such as exp2(3CW), exp10(3CW), or exp16(3CW). Although there is still an exponential function in the final expression, provided that its argument is further reduced exactly to the sum of an integer and a fraction, then that argument is small, and the exponential function error is also expected to be small. The scalbn(3CW) function is exact. The computed result should then be correct to within one or two ulps (units in the last place).m = logb(x) + 1 g = scalbn(x, -m) x = g * beta**m f = logbfact(n, &j) log[beta](n!) = f + j log[beta](x**(-a)) = -a * log[beta](x) = -a * (m + log[beta](g)) log[beta](x**(-a) * n!) = j + f - a * m - a * log[beta](g) x**(-a) * n! = beta**(log[beta](x**(-a) * n!) = beta**j * beta**(f - a * m - a * log[beta](g)) = scalbn(expbeta(f - a * m - a * log[beta](g)), j)
The logbfact(3CW) function family guarantees often-correctly-rounded results for factorials up to (2n)!, where n! is just below the overflow limit, and the results are obtained by fast table lookup, with at worst one logarithm evaluation. For larger arguments, the log-gamma approach is used.