(root)/
glibc-2.38/
sysdeps/
ieee754/
dbl-64/
e_gamma_r.c
       1  /* Implementation of gamma function according to ISO C.
       2     Copyright (C) 1997-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <math.h>
      20  #include <math-narrow-eval.h>
      21  #include <math_private.h>
      22  #include <fenv_private.h>
      23  #include <math-underflow.h>
      24  #include <float.h>
      25  #include <libm-alias-finite.h>
      26  #include <mul_split.h>
      27  
      28  /* Coefficients B_2k / 2k(2k-1) of x^-(2k-1) inside exp in Stirling's
      29     approximation to gamma function.  */
      30  
      31  static const double gamma_coeff[] =
      32    {
      33      0x1.5555555555555p-4,
      34      -0xb.60b60b60b60b8p-12,
      35      0x3.4034034034034p-12,
      36      -0x2.7027027027028p-12,
      37      0x3.72a3c5631fe46p-12,
      38      -0x7.daac36664f1f4p-12,
      39    };
      40  
      41  #define NCOEFF (sizeof (gamma_coeff) / sizeof (gamma_coeff[0]))
      42  
      43  /* Return gamma (X), for positive X less than 184, in the form R *
      44     2^(*EXP2_ADJ), where R is the return value and *EXP2_ADJ is set to
      45     avoid overflow or underflow in intermediate calculations.  */
      46  
      47  static double
      48  gamma_positive (double x, int *exp2_adj)
      49  {
      50    int local_signgam;
      51    if (x < 0.5)
      52      {
      53        *exp2_adj = 0;
      54        return __ieee754_exp (__ieee754_lgamma_r (x + 1, &local_signgam)) / x;
      55      }
      56    else if (x <= 1.5)
      57      {
      58        *exp2_adj = 0;
      59        return __ieee754_exp (__ieee754_lgamma_r (x, &local_signgam));
      60      }
      61    else if (x < 6.5)
      62      {
      63        /* Adjust into the range for using exp (lgamma).  */
      64        *exp2_adj = 0;
      65        double n = ceil (x - 1.5);
      66        double x_adj = x - n;
      67        double eps;
      68        double prod = __gamma_product (x_adj, 0, n, &eps);
      69        return (__ieee754_exp (__ieee754_lgamma_r (x_adj, &local_signgam))
      70  	      * prod * (1.0 + eps));
      71      }
      72    else
      73      {
      74        double eps = 0;
      75        double x_eps = 0;
      76        double x_adj = x;
      77        double prod = 1;
      78        if (x < 12.0)
      79  	{
      80  	  /* Adjust into the range for applying Stirling's
      81  	     approximation.  */
      82  	  double n = ceil (12.0 - x);
      83  	  x_adj = math_narrow_eval (x + n);
      84  	  x_eps = (x - (x_adj - n));
      85  	  prod = __gamma_product (x_adj - n, x_eps, n, &eps);
      86  	}
      87        /* The result is now gamma (X_ADJ + X_EPS) / (PROD * (1 + EPS)).
      88  	 Compute gamma (X_ADJ + X_EPS) using Stirling's approximation,
      89  	 starting by computing pow (X_ADJ, X_ADJ) with a power of 2
      90  	 factored out.  */
      91        double x_adj_int = round (x_adj);
      92        double x_adj_frac = x_adj - x_adj_int;
      93        int x_adj_log2;
      94        double x_adj_mant = __frexp (x_adj, &x_adj_log2);
      95        if (x_adj_mant < M_SQRT1_2)
      96  	{
      97  	  x_adj_log2--;
      98  	  x_adj_mant *= 2.0;
      99  	}
     100        *exp2_adj = x_adj_log2 * (int) x_adj_int;
     101        double h1, l1, h2, l2;
     102        mul_split (&h1, &l1, __ieee754_pow (x_adj_mant, x_adj),
     103  			   __ieee754_exp2 (x_adj_log2 * x_adj_frac));
     104        mul_split (&h2, &l2, __ieee754_exp (-x_adj), sqrt (2 * M_PI / x_adj));
     105        mul_expansion (&h1, &l1, h1, l1, h2, l2);
     106        /* Divide by prod * (1 + eps).  */
     107        div_expansion (&h1, &l1, h1, l1, prod, prod * eps);
     108        double exp_adj = x_eps * __ieee754_log (x_adj);
     109        double bsum = gamma_coeff[NCOEFF - 1];
     110        double x_adj2 = x_adj * x_adj;
     111        for (size_t i = 1; i <= NCOEFF - 1; i++)
     112  	bsum = bsum / x_adj2 + gamma_coeff[NCOEFF - 1 - i];
     113        exp_adj += bsum / x_adj;
     114        /* Now return (h1+l1) * exp(exp_adj), where exp_adj is small.  */
     115        l1 += h1 * __expm1 (exp_adj);
     116        return h1 + l1;
     117      }
     118  }
     119  
     120  double
     121  __ieee754_gamma_r (double x, int *signgamp)
     122  {
     123    int32_t hx;
     124    uint32_t lx;
     125    double ret;
     126  
     127    EXTRACT_WORDS (hx, lx, x);
     128  
     129    if (__glibc_unlikely (((hx & 0x7fffffff) | lx) == 0))
     130      {
     131        /* Return value for x == 0 is Inf with divide by zero exception.  */
     132        *signgamp = 0;
     133        return 1.0 / x;
     134      }
     135    if (__builtin_expect (hx < 0, 0)
     136        && (uint32_t) hx < 0xfff00000 && rint (x) == x)
     137      {
     138        /* Return value for integer x < 0 is NaN with invalid exception.  */
     139        *signgamp = 0;
     140        return (x - x) / (x - x);
     141      }
     142    if (__glibc_unlikely ((unsigned int) hx == 0xfff00000 && lx == 0))
     143      {
     144        /* x == -Inf.  According to ISO this is NaN.  */
     145        *signgamp = 0;
     146        return x - x;
     147      }
     148    if (__glibc_unlikely ((hx & 0x7ff00000) == 0x7ff00000))
     149      {
     150        /* Positive infinity (return positive infinity) or NaN (return
     151  	 NaN).  */
     152        *signgamp = 0;
     153        return x + x;
     154      }
     155  
     156    if (x >= 172.0)
     157      {
     158        /* Overflow.  */
     159        *signgamp = 0;
     160        ret = math_narrow_eval (DBL_MAX * DBL_MAX);
     161        return ret;
     162      }
     163    else
     164      {
     165        SET_RESTORE_ROUND (FE_TONEAREST);
     166        if (x > 0.0)
     167  	{
     168  	  *signgamp = 0;
     169  	  int exp2_adj;
     170  	  double tret = gamma_positive (x, &exp2_adj);
     171  	  ret = __scalbn (tret, exp2_adj);
     172  	}
     173        else if (x >= -DBL_EPSILON / 4.0)
     174  	{
     175  	  *signgamp = 0;
     176  	  ret = 1.0 / x;
     177  	}
     178        else
     179  	{
     180  	  double tx = trunc (x);
     181  	  *signgamp = (tx == 2.0 * trunc (tx / 2.0)) ? -1 : 1;
     182  	  if (x <= -184.0)
     183  	    /* Underflow.  */
     184  	    ret = DBL_MIN * DBL_MIN;
     185  	  else
     186  	    {
     187  	      double frac = tx - x;
     188  	      if (frac > 0.5)
     189  		frac = 1.0 - frac;
     190  	      double sinpix = (frac <= 0.25
     191  			       ? __sin (M_PI * frac)
     192  			       : __cos (M_PI * (0.5 - frac)));
     193  	      int exp2_adj;
     194  	      double h1, l1, h2, l2;
     195  	      h2 = gamma_positive (-x, &exp2_adj);
     196  	      mul_split (&h1, &l1, sinpix, h2);
     197  	      /* sinpix*gamma_positive(.) = h1 + l1 */
     198  	      mul_split (&h2, &l2, h1, x);
     199  	      /* h1*x = h2 + l2 */
     200  	      /* (h1 + l1) * x = h1*x + l1*x = h2 + l2 + l1*x */
     201  	      l2 += l1 * x;
     202  	      /* x*sinpix*gamma_positive(.) ~ h2 + l2 */
     203  	      h1 = 0x3.243f6a8885a3p+0;   /* binary64 approximation of Pi */
     204  	      l1 = 0x8.d313198a2e038p-56; /* |h1+l1-Pi| < 3e-33 */
     205  	      /* Now we divide h1 + l1 by h2 + l2.  */
     206  	      div_expansion (&h1, &l1, h1, l1, h2, l2);
     207  	      ret = __scalbn (-h1, -exp2_adj);
     208  	      math_check_force_underflow_nonneg (ret);
     209  	    }
     210  	}
     211        ret = math_narrow_eval (ret);
     212      }
     213    if (isinf (ret) && x != 0)
     214      {
     215        if (*signgamp < 0)
     216  	{
     217  	  ret = math_narrow_eval (-copysign (DBL_MAX, ret) * DBL_MAX);
     218  	  ret = -ret;
     219  	}
     220        else
     221  	ret = math_narrow_eval (copysign (DBL_MAX, ret) * DBL_MAX);
     222        return ret;
     223      }
     224    else if (ret == 0)
     225      {
     226        if (*signgamp < 0)
     227  	{
     228  	  ret = math_narrow_eval (-copysign (DBL_MIN, ret) * DBL_MIN);
     229  	  ret = -ret;
     230  	}
     231        else
     232  	ret = math_narrow_eval (copysign (DBL_MIN, ret) * DBL_MIN);
     233        return ret;
     234      }
     235    else
     236      return ret;
     237  }
     238  libm_alias_finite (__ieee754_gamma_r, __gamma_r)