Blame specfunc/poch.c

Packit 67cb25
/* specfunc/poch.c
Packit 67cb25
 * 
Packit 67cb25
 * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
Packit 67cb25
 * Copyright (C) 2009 Brian Gough
Packit 67cb25
 * 
Packit 67cb25
 * This program is free software; you can redistribute it and/or modify
Packit 67cb25
 * it under the terms of the GNU General Public License as published by
Packit 67cb25
 * the Free Software Foundation; either version 3 of the License, or (at
Packit 67cb25
 * your option) any later version.
Packit 67cb25
 * 
Packit 67cb25
 * This program is distributed in the hope that it will be useful, but
Packit 67cb25
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 67cb25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 67cb25
 * General Public License for more details.
Packit 67cb25
 * 
Packit 67cb25
 * You should have received a copy of the GNU General Public License
Packit 67cb25
 * along with this program; if not, write to the Free Software
Packit 67cb25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 67cb25
 */
Packit 67cb25
Packit 67cb25
/* Author:  G. Jungman */
Packit 67cb25
Packit 67cb25
#include <config.h>
Packit 67cb25
#include <gsl/gsl_math.h>
Packit 67cb25
#include <gsl/gsl_errno.h>
Packit 67cb25
#include <gsl/gsl_sf_exp.h>
Packit 67cb25
#include <gsl/gsl_sf_log.h>
Packit 67cb25
#include <gsl/gsl_sf_pow_int.h>
Packit 67cb25
#include <gsl/gsl_sf_psi.h>
Packit 67cb25
#include <gsl/gsl_sf_gamma.h>
Packit 67cb25
Packit 67cb25
#include "error.h"
Packit 67cb25
Packit 67cb25
static const double bern[21] = {
Packit 67cb25
   0.0   /* no element 0 */,  
Packit 67cb25
  +0.833333333333333333333333333333333e-01,
Packit 67cb25
  -0.138888888888888888888888888888888e-02,
Packit 67cb25
  +0.330687830687830687830687830687830e-04,
Packit 67cb25
  -0.826719576719576719576719576719576e-06,
Packit 67cb25
  +0.208767569878680989792100903212014e-07,
Packit 67cb25
  -0.528419013868749318484768220217955e-09,
Packit 67cb25
  +0.133825365306846788328269809751291e-10,
Packit 67cb25
  -0.338968029632258286683019539124944e-12,
Packit 67cb25
  +0.858606205627784456413590545042562e-14,
Packit 67cb25
  -0.217486869855806187304151642386591e-15,
Packit 67cb25
  +0.550900282836022951520265260890225e-17,
Packit 67cb25
  -0.139544646858125233407076862640635e-18,
Packit 67cb25
  +0.353470703962946747169322997780379e-20,
Packit 67cb25
  -0.895351742703754685040261131811274e-22,
Packit 67cb25
  +0.226795245233768306031095073886816e-23,
Packit 67cb25
  -0.574472439520264523834847971943400e-24,
Packit 67cb25
  +0.145517247561486490186626486727132e-26,
Packit 67cb25
  -0.368599494066531017818178247990866e-28,
Packit 67cb25
  +0.933673425709504467203255515278562e-30,
Packit 67cb25
  -0.236502241570062993455963519636983e-31
Packit 67cb25
};
Packit 67cb25
Packit 67cb25
Packit 67cb25
/* ((a)_x - 1)/x in the "small x" region where
Packit 67cb25
 * cancellation must be controlled.
Packit 67cb25
 *
Packit 67cb25
 * Based on SLATEC DPOCH1().
Packit 67cb25
 */
Packit 67cb25
/*
Packit 67cb25
C When ABS(X) is so small that substantial cancellation will occur if
Packit 67cb25
C the straightforward formula is used, we use an expansion due
Packit 67cb25
C to Fields and discussed by Y. L. Luke, The Special Functions and Their
Packit 67cb25
C Approximations, Vol. 1, Academic Press, 1969, page 34.
Packit 67cb25
C
Packit 67cb25
C The ratio POCH(A,X) = GAMMA(A+X)/GAMMA(A) is written by Luke as
Packit 67cb25
C        (A+(X-1)/2)**X * polynomial in (A+(X-1)/2)**(-2) .
Packit 67cb25
C In order to maintain significance in POCH1, we write for positive a
Packit 67cb25
C        (A+(X-1)/2)**X = EXP(X*LOG(A+(X-1)/2)) = EXP(Q)
Packit 67cb25
C                       = 1.0 + Q*EXPREL(Q) .
Packit 67cb25
C Likewise the polynomial is written
Packit 67cb25
C        POLY = 1.0 + X*POLY1(A,X) .
Packit 67cb25
C Thus,
Packit 67cb25
C        POCH1(A,X) = (POCH(A,X) - 1) / X
Packit 67cb25
C                   = EXPREL(Q)*(Q/X + Q*POLY1(A,X)) + POLY1(A,X)
Packit 67cb25
C
Packit 67cb25
*/
Packit 67cb25
static
Packit 67cb25
int
Packit 67cb25
pochrel_smallx(const double a, const double x, gsl_sf_result * result)
Packit 67cb25
{
Packit 67cb25
  /*
Packit 67cb25
   SQTBIG = 1.0D0/SQRT(24.0D0*D1MACH(1))
Packit 67cb25
   ALNEPS = LOG(D1MACH(3))
Packit 67cb25
   */
Packit 67cb25
  const double SQTBIG = 1.0/(2.0*M_SQRT2*M_SQRT3*GSL_SQRT_DBL_MIN);
Packit 67cb25
  const double ALNEPS = GSL_LOG_DBL_EPSILON - M_LN2;
Packit 67cb25
Packit 67cb25
  if(x == 0.0) {
Packit 67cb25
    return gsl_sf_psi_e(a, result);
Packit 67cb25
  }
Packit 67cb25
  else {
Packit 67cb25
    const double bp   = (  (a < -0.5) ? 1.0-a-x : a );
Packit 67cb25
    const int    incr = ( (bp < 10.0) ? 11.0-bp : 0 );
Packit 67cb25
    const double b    = bp + incr;
Packit 67cb25
    double dpoch1;
Packit 67cb25
    gsl_sf_result dexprl;
Packit 67cb25
    int stat_dexprl;
Packit 67cb25
    int i;
Packit 67cb25
Packit 67cb25
    double var    = b + 0.5*(x-1.0);
Packit 67cb25
    double alnvar = log(var);
Packit 67cb25
    double q = x*alnvar;
Packit 67cb25
Packit 67cb25
    double poly1 = 0.0;
Packit 67cb25
Packit 67cb25
    if(var < SQTBIG) {
Packit 67cb25
      const int nterms = (int)(-0.5*ALNEPS/alnvar + 1.0);
Packit 67cb25
      const double var2 = (1.0/var)/var;
Packit 67cb25
      const double rho  = 0.5 * (x + 1.0);
Packit 67cb25
      double term = var2;
Packit 67cb25
      double gbern[24];
Packit 67cb25
      int k, j;
Packit 67cb25
Packit 67cb25
      gbern[1] = 1.0;
Packit 67cb25
      gbern[2] = -rho/12.0;
Packit 67cb25
      poly1 = gbern[2] * term;
Packit 67cb25
Packit 67cb25
      if(nterms > 20) {
Packit 67cb25
        /* NTERMS IS TOO BIG, MAYBE D1MACH(3) IS BAD */
Packit 67cb25
        /* nterms = 20; */
Packit 67cb25
        result->val = 0.0;
Packit 67cb25
        result->err = 0.0;
Packit 67cb25
        GSL_ERROR ("error", GSL_ESANITY);
Packit 67cb25
      }
Packit 67cb25
Packit 67cb25
      for(k=2; k<=nterms; k++) {
Packit 67cb25
        double gbk = 0.0;
Packit 67cb25
        for(j=1; j<=k; j++) {
Packit 67cb25
          gbk += bern[k-j+1]*gbern[j];
Packit 67cb25
        }
Packit 67cb25
        gbern[k+1] = -rho*gbk/k;
Packit 67cb25
Packit 67cb25
        term  *= (2*k-2-x)*(2*k-1-x)*var2;
Packit 67cb25
        poly1 += gbern[k+1]*term;
Packit 67cb25
      }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
    stat_dexprl = gsl_sf_expm1_e(q, &dexprl);
Packit 67cb25
    if(stat_dexprl != GSL_SUCCESS) {
Packit 67cb25
      result->val = 0.0;
Packit 67cb25
      result->err = 0.0;
Packit 67cb25
      return stat_dexprl;
Packit 67cb25
    }
Packit 67cb25
    dexprl.val = dexprl.val/q;
Packit 67cb25
    poly1 *= (x - 1.0);
Packit 67cb25
    dpoch1 = dexprl.val * (alnvar + q * poly1) + poly1;
Packit 67cb25
Packit 67cb25
    for(i=incr-1; i >= 0; i--) {
Packit 67cb25
      /*
Packit 67cb25
       C WE HAVE DPOCH1(B,X), BUT BP IS SMALL, SO WE USE BACKWARDS RECURSION
Packit 67cb25
       C TO OBTAIN DPOCH1(BP,X).
Packit 67cb25
       */
Packit 67cb25
      double binv = 1.0/(bp+i);
Packit 67cb25
      dpoch1 = (dpoch1 - binv) / (1.0 + x*binv);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
    if(bp == a) {
Packit 67cb25
      result->val = dpoch1;
Packit 67cb25
      result->err = 2.0 * GSL_DBL_EPSILON * (fabs(incr) + 1.0) * fabs(result->val);
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
    else {
Packit 67cb25
      /*
Packit 67cb25
       C WE HAVE DPOCH1(BP,X), BUT A IS LT -0.5.  WE THEREFORE USE A
Packit 67cb25
       C REFLECTION FORMULA TO OBTAIN DPOCH1(A,X).
Packit 67cb25
       */
Packit 67cb25
      double sinpxx = sin(M_PI*x)/x;
Packit 67cb25
      double sinpx2 = sin(0.5*M_PI*x);
Packit 67cb25
      double t1 = sinpxx/tan(M_PI*b);
Packit 67cb25
      double t2 = 2.0*sinpx2*(sinpx2/x);
Packit 67cb25
      double trig  = t1 - t2;
Packit 67cb25
      result->val  = dpoch1 * (1.0 + x*trig) + trig;
Packit 67cb25
      result->err  = (fabs(dpoch1*x) + 1.0) * GSL_DBL_EPSILON * (fabs(t1) + fabs(t2));
Packit 67cb25
      result->err += 2.0 * GSL_DBL_EPSILON * (fabs(incr) + 1.0) * fabs(result->val);
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }    
Packit 67cb25
  }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
Packit 67cb25
/* Assumes a>0 and a+x>0.
Packit 67cb25
 */
Packit 67cb25
static
Packit 67cb25
int
Packit 67cb25
lnpoch_pos(const double a, const double x, gsl_sf_result * result)
Packit 67cb25
{
Packit 67cb25
  double absx = fabs(x);
Packit 67cb25
Packit 67cb25
  if(absx > 0.1*a || absx*log(GSL_MAX_DBL(a,2.0)) > 0.1) {
Packit 67cb25
    if(a < GSL_SF_GAMMA_XMAX && a+x < GSL_SF_GAMMA_XMAX) {
Packit 67cb25
      /* If we can do it by calculating the gamma functions
Packit 67cb25
       * directly, then that will be more accurate than
Packit 67cb25
       * doing the subtraction of the logs.
Packit 67cb25
       */
Packit 67cb25
      gsl_sf_result g1;
Packit 67cb25
      gsl_sf_result g2;
Packit 67cb25
      gsl_sf_gammainv_e(a,   &g1;;
Packit 67cb25
      gsl_sf_gammainv_e(a+x, &g2;;
Packit 67cb25
      result->val  = -log(g2.val/g1.val);
Packit 67cb25
      result->err  = g1.err/fabs(g1.val) + g2.err/fabs(g2.val);
Packit 67cb25
      result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
    else {
Packit 67cb25
      /* Otherwise we must do the subtraction.
Packit 67cb25
       */
Packit 67cb25
      gsl_sf_result lg1;
Packit 67cb25
      gsl_sf_result lg2;
Packit 67cb25
      int stat_1 = gsl_sf_lngamma_e(a,   &lg1;;
Packit 67cb25
      int stat_2 = gsl_sf_lngamma_e(a+x, &lg2;;
Packit 67cb25
      result->val  = lg2.val - lg1.val;
Packit 67cb25
      result->err  = lg2.err + lg1.err;
Packit 67cb25
      result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
Packit 67cb25
      return GSL_ERROR_SELECT_2(stat_1, stat_2);
Packit 67cb25
    }
Packit 67cb25
  }
Packit 67cb25
  else if(absx < 0.1*a && a > 15.0) {
Packit 67cb25
    /* Be careful about the implied subtraction.
Packit 67cb25
     * Note that both a+x and and a must be
Packit 67cb25
     * large here since a is not small
Packit 67cb25
     * and x is not relatively large.
Packit 67cb25
     * So we calculate using Stirling for Log[Gamma(z)].
Packit 67cb25
     *
Packit 67cb25
     *   Log[Gamma(a+x)/Gamma(a)] = x(Log[a]-1) + (x+a-1/2)Log[1+x/a]
Packit 67cb25
     *                              + (1/(1+eps)   - 1) / (12 a)
Packit 67cb25
     *                              - (1/(1+eps)^3 - 1) / (360 a^3)
Packit 67cb25
     *                              + (1/(1+eps)^5 - 1) / (1260 a^5)
Packit 67cb25
     *                              - (1/(1+eps)^7 - 1) / (1680 a^7)
Packit 67cb25
     *                              + ...
Packit 67cb25
     */
Packit 67cb25
    const double eps = x/a;
Packit 67cb25
    const double den = 1.0 + eps;
Packit 67cb25
    const double d3 = den*den*den;
Packit 67cb25
    const double d5 = d3*den*den;
Packit 67cb25
    const double d7 = d5*den*den;
Packit 67cb25
    const double c1 = -eps/den;
Packit 67cb25
    const double c3 = -eps*(3.0+eps*(3.0+eps))/d3;
Packit 67cb25
    const double c5 = -eps*(5.0+eps*(10.0+eps*(10.0+eps*(5.0+eps))))/d5;
Packit 67cb25
    const double c7 = -eps*(7.0+eps*(21.0+eps*(35.0+eps*(35.0+eps*(21.0+eps*(7.0+eps))))))/d7;
Packit 67cb25
    const double p8 = gsl_sf_pow_int(1.0+eps,8);
Packit 67cb25
    const double c8 = 1.0/p8             - 1.0;  /* these need not   */
Packit 67cb25
    const double c9 = 1.0/(p8*(1.0+eps)) - 1.0;  /* be very accurate */
Packit 67cb25
    const double a4 = a*a*a*a;
Packit 67cb25
    const double a6 = a4*a*a;
Packit 67cb25
    const double ser_1 = c1 + c3/(30.0*a*a) + c5/(105.0*a4) + c7/(140.0*a6);
Packit 67cb25
    const double ser_2 = c8/(99.0*a6*a*a) - 691.0/360360.0 * c9/(a6*a4);
Packit 67cb25
    const double ser = (ser_1 + ser_2)/ (12.0*a);
Packit 67cb25
Packit 67cb25
    double term1 = x * log(a/M_E);
Packit 67cb25
    double term2;
Packit 67cb25
    gsl_sf_result ln_1peps;
Packit 67cb25
    gsl_sf_log_1plusx_e(eps, &ln_1peps);  /* log(1 + x/a) */
Packit 67cb25
    term2 = (x + a - 0.5) * ln_1peps.val;
Packit 67cb25
Packit 67cb25
    result->val  = term1 + term2 + ser;
Packit 67cb25
    result->err  = GSL_DBL_EPSILON*fabs(term1);
Packit 67cb25
    result->err += fabs((x + a - 0.5)*ln_1peps.err);
Packit 67cb25
    result->err += fabs(ln_1peps.val) * GSL_DBL_EPSILON * (fabs(x) + fabs(a) + 0.5);
Packit 67cb25
    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
Packit 67cb25
    return GSL_SUCCESS;
Packit 67cb25
  }
Packit 67cb25
  else {
Packit 67cb25
    gsl_sf_result poch_rel;
Packit 67cb25
    int stat_p = pochrel_smallx(a, x, &poch_rel);
Packit 67cb25
    double eps = x*poch_rel.val;
Packit 67cb25
    int stat_e = gsl_sf_log_1plusx_e(eps, result);
Packit 67cb25
    result->err  = 2.0 * fabs(x * poch_rel.err / (1.0 + eps));
Packit 67cb25
    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
Packit 67cb25
    return GSL_ERROR_SELECT_2(stat_e, stat_p);
Packit 67cb25
  }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
Packit 67cb25
/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_sf_lnpoch_e(const double a, const double x, gsl_sf_result * result)
Packit 67cb25
{
Packit 67cb25
  /* CHECK_POINTER(result) */
Packit 67cb25
Packit 67cb25
  if(a <= 0.0 || a+x <= 0.0) {
Packit 67cb25
    DOMAIN_ERROR(result);
Packit 67cb25
  }
Packit 67cb25
  else if(x == 0.0) {
Packit 67cb25
    result->val = 0.0;
Packit 67cb25
    result->err = 0.0;
Packit 67cb25
    return GSL_SUCCESS;
Packit 67cb25
  }
Packit 67cb25
  else {
Packit 67cb25
    return lnpoch_pos(a, x, result);
Packit 67cb25
  }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_sf_lnpoch_sgn_e(const double a, const double x,
Packit 67cb25
                       gsl_sf_result * result, double * sgn)
Packit 67cb25
{
Packit 67cb25
  if(x == 0.0) {
Packit 67cb25
    *sgn = 1.0;
Packit 67cb25
    result->val = 0.0;
Packit 67cb25
    result->err = 0.0;
Packit 67cb25
    return GSL_SUCCESS;
Packit 67cb25
  }
Packit 67cb25
  else if(a > 0.0 && a+x > 0.0) {
Packit 67cb25
    *sgn = 1.0;
Packit 67cb25
    return lnpoch_pos(a, x, result);
Packit 67cb25
  }
Packit 67cb25
  else if (a <= 0 && a == floor(a)) {
Packit 67cb25
    /* Special cases for infinite denominator Gamma(a) */
Packit 67cb25
    if (a + x < 0  && x == floor(x)) {
Packit 67cb25
      /* Handle the case where both a and a+x are negative integers. */
Packit 67cb25
      gsl_sf_result result_pos;
Packit 67cb25
      /* Use the reflection formula AMS6.1.17
Packit 67cb25
         poch(-a,-x) = (-1)^x (a/(a+x)) 1/poch(a,x) */
Packit 67cb25
      int stat = lnpoch_pos (-a, -x, &result_pos);
Packit 67cb25
      double f = log (a / (a + x));
Packit 67cb25
      double s = (fmod(x, 2) == 0) ? 1 : -1;
Packit 67cb25
      result->val = f - result_pos.val;
Packit 67cb25
      result->err = result_pos.err + 2.0 * GSL_DBL_EPSILON * f;
Packit 67cb25
      *sgn = s;
Packit 67cb25
      return stat;
Packit 67cb25
    } else if (a + x == 0) {
Packit 67cb25
      /* Handle a+x = 0 i.e. Gamma(0)/Gamma(a) */
Packit 67cb25
      /* poch (-a,a) == (-1)^a Gamma(a+1) */
Packit 67cb25
      int stat = gsl_sf_lngamma_sgn_e (-a + 1, result, sgn);
Packit 67cb25
      double s = (fmod(-a, 2) == 0) ? 1 : -1;
Packit 67cb25
      *sgn *= s;
Packit 67cb25
      return stat;
Packit 67cb25
    } else {
Packit 67cb25
      /* Handle finite numerator, Gamma(a+x) for a+x != 0 or neg int */
Packit 67cb25
      result->val = GSL_NEGINF;
Packit 67cb25
      result->err = 0.0;
Packit 67cb25
      *sgn = 1;
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
  } else if(a < 0.0 && a+x < 0.0) {
Packit 67cb25
    /* Reduce to positive case using reflection.
Packit 67cb25
     */
Packit 67cb25
    double sin_1 = sin(M_PI * (1.0 - a));
Packit 67cb25
    double sin_2 = sin(M_PI * (1.0 - a - x));
Packit 67cb25
    if(sin_1 == 0.0 || sin_2 == 0.0) {
Packit 67cb25
      *sgn = 0.0;
Packit 67cb25
      DOMAIN_ERROR(result);
Packit 67cb25
    }
Packit 67cb25
    else {
Packit 67cb25
      gsl_sf_result lnp_pos;
Packit 67cb25
      int stat_pp   = lnpoch_pos(1.0-a, -x, &lnp_pos);
Packit 67cb25
      double lnterm = log(fabs(sin_1/sin_2));
Packit 67cb25
      result->val  = lnterm - lnp_pos.val;
Packit 67cb25
      result->err  = lnp_pos.err;
Packit 67cb25
      result->err += 2.0 * GSL_DBL_EPSILON * (fabs(1.0-a) + fabs(1.0-a-x)) * fabs(lnterm);
Packit 67cb25
      result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
Packit 67cb25
      *sgn = GSL_SIGN(sin_1*sin_2);
Packit 67cb25
      return stat_pp;
Packit 67cb25
    }
Packit 67cb25
  }
Packit 67cb25
  else {
Packit 67cb25
    /* Evaluate gamma ratio directly.
Packit 67cb25
     */
Packit 67cb25
    gsl_sf_result lg_apn;
Packit 67cb25
    gsl_sf_result lg_a;
Packit 67cb25
    double s_apn, s_a;
Packit 67cb25
    int stat_apn = gsl_sf_lngamma_sgn_e(a+x, &lg_apn, &s_apn);
Packit 67cb25
    int stat_a   = gsl_sf_lngamma_sgn_e(a,   &lg_a,   &s_a);
Packit 67cb25
    if(stat_apn == GSL_SUCCESS && stat_a == GSL_SUCCESS) {
Packit 67cb25
      result->val  = lg_apn.val - lg_a.val;
Packit 67cb25
      result->err  = lg_apn.err + lg_a.err;
Packit 67cb25
      result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
Packit 67cb25
      *sgn = s_a * s_apn;
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
    else if(stat_apn == GSL_EDOM || stat_a == GSL_EDOM){
Packit 67cb25
      *sgn = 0.0;
Packit 67cb25
      DOMAIN_ERROR(result);
Packit 67cb25
    }
Packit 67cb25
    else {
Packit 67cb25
      result->val = 0.0;
Packit 67cb25
      result->err = 0.0;
Packit 67cb25
      *sgn = 0.0;
Packit 67cb25
      return GSL_FAILURE;
Packit 67cb25
    }
Packit 67cb25
  }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_sf_poch_e(const double a, const double x, gsl_sf_result * result)
Packit 67cb25
{
Packit 67cb25
  /* CHECK_POINTER(result) */
Packit 67cb25
Packit 67cb25
  if(x == 0.0) {
Packit 67cb25
    result->val = 1.0;
Packit 67cb25
    result->err = 0.0;
Packit 67cb25
    return GSL_SUCCESS;
Packit 67cb25
  } else {
Packit 67cb25
    gsl_sf_result lnpoch;
Packit 67cb25
    double sgn;
Packit 67cb25
    int stat_lnpoch = gsl_sf_lnpoch_sgn_e(a, x, &lnpoch, &sgn);
Packit 67cb25
    if (lnpoch.val == GSL_NEGINF) {
Packit 67cb25
      result->val = 0;
Packit 67cb25
      result->err = 0;
Packit 67cb25
      return stat_lnpoch;
Packit 67cb25
    } else {
Packit 67cb25
      int stat_exp    = gsl_sf_exp_err_e(lnpoch.val, lnpoch.err, result);
Packit 67cb25
      result->val *= sgn;
Packit 67cb25
      result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
Packit 67cb25
      return GSL_ERROR_SELECT_2(stat_exp, stat_lnpoch);
Packit 67cb25
    }
Packit 67cb25
  }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_sf_pochrel_e(const double a, const double x, gsl_sf_result * result)
Packit 67cb25
{
Packit 67cb25
  const double absx = fabs(x);
Packit 67cb25
  const double absa = fabs(a);
Packit 67cb25
Packit 67cb25
  /* CHECK_POINTER(result) */
Packit 67cb25
Packit 67cb25
  if(absx > 0.1*absa || absx*log(GSL_MAX(absa,2.0)) > 0.1) {
Packit 67cb25
    gsl_sf_result lnpoch;
Packit 67cb25
    double sgn;
Packit 67cb25
    int stat_poch = gsl_sf_lnpoch_sgn_e(a, x, &lnpoch, &sgn);
Packit 67cb25
    if(lnpoch.val > GSL_LOG_DBL_MAX) {
Packit 67cb25
      OVERFLOW_ERROR(result);
Packit 67cb25
    }
Packit 67cb25
    else {
Packit 67cb25
      const double el = exp(lnpoch.val);
Packit 67cb25
      result->val  = (sgn*el - 1.0)/x;
Packit 67cb25
      result->err  = fabs(result->val) * (lnpoch.err + 2.0 * GSL_DBL_EPSILON);
Packit 67cb25
      result->err += 2.0 * GSL_DBL_EPSILON * (fabs(sgn*el) + 1.0) / fabs(x);
Packit 67cb25
      return stat_poch;
Packit 67cb25
    }
Packit 67cb25
  }
Packit 67cb25
  else {
Packit 67cb25
    return pochrel_smallx(a, x, result);
Packit 67cb25
  }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
Packit 67cb25
/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/
Packit 67cb25
Packit 67cb25
#include "eval.h"
Packit 67cb25
Packit 67cb25
double gsl_sf_lnpoch(const double a, const double x)
Packit 67cb25
{
Packit 67cb25
  EVAL_RESULT(gsl_sf_lnpoch_e(a, x, &result));
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
double gsl_sf_poch(const double a, const double x)
Packit 67cb25
{
Packit 67cb25
  EVAL_RESULT(gsl_sf_poch_e(a, x, &result));
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
double gsl_sf_pochrel(const double a, const double x)
Packit 67cb25
{
Packit 67cb25
  EVAL_RESULT(gsl_sf_pochrel_e(a, x, &result));
Packit 67cb25
}