float __ieee754_gammaf_r (float x, int *signgamp) { /* We don't have a real gamma implementation now. We'll use lgamma and the exp function. But due to the required boundary conditions we must check some values separately. */ int32_t hx; GET_FLOAT_WORD (hx, x); if (__builtin_expect ((hx & 0x7fffffff) == 0, 0)) { /* Return value for x == 0 is Inf with divide by zero exception. */ *signgamp = 0; return 1.0 / x; } if (__builtin_expect (hx < 0, 0) && (u_int32_t) hx < 0xff800000 && __rintf (x) == x) { /* Return value for integer x < 0 is NaN with invalid exception. */ *signgamp = 0; return (x - x) / (x - x); } if (__builtin_expect (hx == 0xff800000, 0)) { /* x == -Inf. According to ISO this is NaN. */ *signgamp = 0; return x - x; } /* XXX FIXME. */ return __ieee754_expf (__ieee754_lgammaf_r (x, signgamp)); }
DLLEXPORT float __ieee754_lgammaf(float x) { #ifdef OPENLIBM_ONLY_THREAD_SAFE int signgam; #endif return __ieee754_lgammaf_r(x,&signgam); }
float lgammaf_r(float x, int *signgamp) /* wrapper lgammaf_r */ { #ifdef _IEEE_LIBM return __ieee754_lgammaf_r(x,signgamp); #else float y; y = __ieee754_lgammaf_r(x,signgamp); if(_LIB_VERSION == _IEEE_) return y; if(!finitef(y)&&finitef(x)) { if(floorf(x)==x&&x<=(float)0.0) /* lgamma pole */ return (float)__kernel_standard((double)x,(double)x,115); else /* lgamma overflow */ return (float)__kernel_standard((double)x,(double)x,114); } else return y; #endif }
float gammaf(float x) { #ifdef _IEEE_LIBM return __ieee754_lgammaf_r(x,&signgam); #else float y; y = __ieee754_lgammaf_r(x,&signgam); if(_LIB_VERSION == _IEEE_) return y; if(!finitef(y)&&finitef(x)) { if(floorf(x)==x&&x<=(float)0.0) /* gammaf pole */ return (float)__kernel_standard((double)x,(double)x,141); else /* gammaf overflow */ return (float)__kernel_standard((double)x,(double)x,140); } else return y; #endif }
float __lgammaf_r(float x, int *signgamp) { float y = __ieee754_lgammaf_r(x,signgamp); if(__builtin_expect(!__finitef(y), 0) && __finitef(x) && _LIB_VERSION != _IEEE_) return __kernel_standard_f(x, x, __floorf(x)==x&&x<=0.0f ? 115 /* lgamma pole */ : 114); /* lgamma overflow */ return y; }
float __ieee754_gammaf_r(float x, int *signgamp) { return __ieee754_lgammaf_r(x,signgamp); }
static float gammaf_positive (float x, int *exp2_adj) { int local_signgam; if (x < 0.5f) { *exp2_adj = 0; return __ieee754_expf (__ieee754_lgammaf_r (x + 1, &local_signgam)) / x; } else if (x <= 1.5f) { *exp2_adj = 0; return __ieee754_expf (__ieee754_lgammaf_r (x, &local_signgam)); } else if (x < 2.5f) { *exp2_adj = 0; float x_adj = x - 1; return (__ieee754_expf (__ieee754_lgammaf_r (x_adj, &local_signgam)) * x_adj); } else { float eps = 0; float x_eps = 0; float x_adj = x; float prod = 1; if (x < 4.0f) { /* Adjust into the range for applying Stirling's approximation. */ float n = __ceilf (4.0f - x); x_adj = math_narrow_eval (x + n); x_eps = (x - (x_adj - n)); prod = __gamma_productf (x_adj - n, x_eps, n, &eps); } /* The result is now gamma (X_ADJ + X_EPS) / (PROD * (1 + EPS)). Compute gamma (X_ADJ + X_EPS) using Stirling's approximation, starting by computing pow (X_ADJ, X_ADJ) with a power of 2 factored out. */ float exp_adj = -eps; float x_adj_int = __roundf (x_adj); float x_adj_frac = x_adj - x_adj_int; int x_adj_log2; float x_adj_mant = __frexpf (x_adj, &x_adj_log2); if (x_adj_mant < (float) M_SQRT1_2) { x_adj_log2--; x_adj_mant *= 2.0f; } *exp2_adj = x_adj_log2 * (int) x_adj_int; float ret = (__ieee754_powf (x_adj_mant, x_adj) * __ieee754_exp2f (x_adj_log2 * x_adj_frac) * __ieee754_expf (-x_adj) * __ieee754_sqrtf (2 * (float) M_PI / x_adj) / prod); exp_adj += x_eps * __ieee754_logf (x_adj); float bsum = gamma_coeff[NCOEFF - 1]; float x_adj2 = x_adj * x_adj; for (size_t i = 1; i <= NCOEFF - 1; i++) bsum = bsum / x_adj2 + gamma_coeff[NCOEFF - 1 - i]; exp_adj += bsum / x_adj; return ret + ret * __expm1f (exp_adj); } }
float __ieee754_lgammaf(float x) { return __ieee754_lgammaf_r(x,&signgam); }
//------------------------------------------------------------------------------ float Cmath::lgammaf( float x ) { float y; struct fexception exc; y = __ieee754_lgammaf_r( x, &m_isigngam ); if( m_fdlib_version == _IEEE_ ) { return y; } if( !finitef( y ) && finitef( x ) ) { exc.name = "lgammaf"; exc.err = 0; exc.arg1 = exc.arg2 = (double)x; if( m_fdlib_version == _SVID_ ) { exc.retval = Huge(); } else { exc.retval = HUGE_VAL; } if( floorf( x ) == x && x <= (float)0.0 ) { // lgammaf(-integer) exc.type = EX_SING; if( m_fdlib_version == _POSIX_ ) { errno = EDOM; } else if( !matherr( &exc ) ) { errno = EDOM; } } else { // lgammaf(finite) overflow exc.type = EX_OVERFLOW; if( m_fdlib_version == _POSIX_ ) { errno = ERANGE; } else if( !matherr( &exc ) ) { errno = ERANGE; } } if( exc.err != 0 ) { errno = exc.err; } return (float)exc.retval; } else { return y; } }
//------------------------------------------------------------------------------ float Cmath::lgammaf_r( float x, int* signgamp ) { float y; struct fexception exc; y = __ieee754_lgammaf_r( x, signgamp ); if( m_fdlib_version == _IEEE_ ) { return y; } if( !finitef( y ) && finitef( x ) ) { # ifndef HUGE_VAL # define HUGE_VAL inf double inf = 0.0; set_high_word( inf, 0x7ff00000 ); // set inf to infinite # endif exc.name = "lgammaf"; exc.err = 0; exc.arg1 = exc.arg2 = (double)x; if( m_fdlib_version == _SVID_ ) { exc.retval = Huge(); } else { exc.retval = HUGE_VAL; } if( floorf( x ) == x && x <= (float)0.0 ) { // lgammaf(-integer) or lgamma(0) exc.type = EX_SING; if( m_fdlib_version == _POSIX_ ) { errno = EDOM; } else if( !matherr( &exc ) ) { errno = EDOM; } } else { // lgammaf(finite) overflow exc.type = EX_OVERFLOW; if( m_fdlib_version == _POSIX_ ) { errno = ERANGE; } else if( !matherr( &exc ) ) { errno = ERANGE; } } if( exc.err != 0 ) { errno = exc.err; } return (float)exc.retval; } else { return y; } }