Example #1
0
double npy_log2(double x)
{
#ifdef HAVE_FREXP
    if (!npy_isfinite(x) || x <= 0.) {
        /* special value result */
        return npy_log(x);
    }
    else {
        /*
         * fallback implementation copied from python3.4 math.log2
         * provides int(log(2**i)) == i for i 1-64 in default rounding mode.
         *
         * We want log2(m * 2**e) == log(m) / log(2) + e.  Care is needed when
         * x is just greater than 1.0: in that case e is 1, log(m) is negative,
         * and we get significant cancellation error from the addition of
         * log(m) / log(2) to e.  The slight rewrite of the expression below
         * avoids this problem.
         */
        int e;
        double m = frexp(x, &e);
        if (x >= 1.0) {
            return log(2.0 * m) / log(2.0) + (e - 1);
        }
        else {
            return log(m) / log(2.0) + e;
        }
    }
#else
    /* does not provide int(log(2**i)) == i */
    return NPY_LOG2E * npy_log(x);
#endif
}
Example #2
0
/*
 * Bessel series
 * http://dlmf.nist.gov/11.4.19
 */
double struve_bessel_series(double v, double z, int is_h, double *err)
{
    int n, sgn;
    double term, cterm, sum, maxterm;

    if (is_h && v < 0) {
        /* Works less reliably in this region */
        *err = NPY_INFINITY;
        return NPY_NAN;
    }

    sum = 0;
    maxterm = 0;

    cterm = sqrt(z / (2*M_PI));

    for (n = 0; n < MAXITER; ++n) {
        if (is_h) {
            term = cterm * bessel_j(n + v + 0.5, z) / (n + 0.5);
            cterm *= z/2 / (n + 1);
        }
        else {
            term = cterm * bessel_i(n + v + 0.5, z) / (n + 0.5);
            cterm *= -z/2 / (n + 1);
        }
        sum += term;
        if (fabs(term) > maxterm) {
            maxterm = fabs(term);
        }
        if (fabs(term) < SUM_EPS * fabs(sum) || term == 0 || !npy_isfinite(sum)) {
            break;
        }
    }

    *err = fabs(term) + fabs(maxterm) * 1e-16;

    /* Account for potential underflow of the Bessel functions */
    *err += 1e-300 * fabs(cterm);

    return sum;
}
Example #3
0
/*
 * Large-z expansion for Struve H and L
 * http://dlmf.nist.gov/11.6.1
 */
double struve_asymp_large_z(double v, double z, int is_h, double *err)
{
    int n, sgn, maxiter;
    double term, sum, maxterm;
    double m;

    if (is_h) {
        sgn = -1;
    }
    else {
        sgn = 1;
    }

    /* Asymptotic expansion divergenge point */
    m = z/2;
    if (m <= 0) {
        maxiter = 0;
    }
    else if (m > MAXITER) {
        maxiter = MAXITER;
    }
    else {
        maxiter = (int)m;
    }
    if (maxiter == 0) {
        *err = NPY_INFINITY;
        return NPY_NAN;
    }

    if (z < v) {
        /* Exclude regions where our error estimation fails */
        *err = NPY_INFINITY;
        return NPY_NAN;
    }

    /* Evaluate sum */
    term = -sgn / sqrt(M_PI) * exp(-lgam(v + 0.5) + (v - 1) * log(z/2)) * gammasgn(v + 0.5);
    sum = term;
    maxterm = 0;

    for (n = 0; n < maxiter; ++n) {
        term *= sgn * (1 + 2*n) * (1 + 2*n - 2*v) / (z*z);
        sum += term;
        if (fabs(term) > maxterm) {
            maxterm = fabs(term);
        }
        if (fabs(term) < SUM_EPS * fabs(sum) || term == 0 || !npy_isfinite(sum)) {
            break;
        }
    }

    if (is_h) {
        sum += bessel_y(v, z);
    }
    else {
        sum += bessel_i(v, z);
    }

    /*
     * This error estimate is strictly speaking valid only for
     * n > v - 0.5, but numerical results indicate that it works
     * reasonably.
     */
    *err = fabs(term) + fabs(maxterm) * 1e-16;

    return sum;
}
Example #4
0
/*
 * Power series for Struve H and L
 * http://dlmf.nist.gov/11.2.1
 *
 * Starts to converge roughly at |n| > |z|
 */
double struve_power_series(double v, double z, int is_h, double *err)
{
    int n, sgn;
    double term, sum, maxterm, scaleexp, tmp;
    double2_t cterm, csum, cdiv, z2, c2v, ctmp, ctmp2;

    if (is_h) {
        sgn = -1;
    }
    else {
        sgn = 1;
    }

    tmp = -lgam(v + 1.5) + (v + 1)*log(z/2);
    if (tmp < -600 || tmp > 600) {
        /* Scale exponent to postpone underflow/overflow */
        scaleexp = tmp/2;
        tmp -= scaleexp;
    }
    else {
        scaleexp = 0;
    }
    
    term = 2 / sqrt(M_PI) * exp(tmp) * gammasgn(v + 1.5);
    sum = term;
    maxterm = 0;

    double2_init(&cterm, term);
    double2_init(&csum, sum);
    double2_init(&z2, sgn*z*z);
    double2_init(&c2v, 2*v);

    for (n = 0; n < MAXITER; ++n) {
        /* cdiv = (3 + 2*n) * (3 + 2*n + 2*v)) */
        double2_init(&cdiv, 3 + 2*n);
        double2_init(&ctmp, 3 + 2*n);
        double2_add(&ctmp, &c2v, &ctmp);
        double2_mul(&cdiv, &ctmp, &cdiv);

        /* cterm *= z2 / cdiv */
        double2_mul(&cterm, &z2, &cterm);
        double2_div(&cterm, &cdiv, &cterm);

        double2_add(&csum, &cterm, &csum);

        term = double2_double(&cterm);
        sum = double2_double(&csum);

        if (fabs(term) > maxterm) {
            maxterm = fabs(term);
        }
        if (fabs(term) < SUM_TINY * fabs(sum) || term == 0 || !npy_isfinite(sum)) {
            break;
        }
    }

    *err = fabs(term) + fabs(maxterm) * 1e-22;

    if (scaleexp != 0) {
        sum *= exp(scaleexp);
        *err *= exp(scaleexp);
    }

    if (sum == 0 && term == 0 && v < 0 && !is_h) {
        /* Spurious underflow */
        *err = NPY_INFINITY;
        return NPY_NAN;
    }

    return sum;
}
Example #5
0
File: gamma.c Project: 317070/scipy
double lgam(double x)
{
    double p, q, u, w, z;
    int i;

    sgngam = 1;

    if (!npy_isfinite(x))
	return x;

    if (x < -34.0) {
	q = -x;
	w = lgam(q);		/* note this modifies sgngam! */
	p = floor(q);
	if (p == q) {
	  lgsing:
	    mtherr("lgam", SING);
	    return (NPY_INFINITY);
	}
	i = p;
	if ((i & 1) == 0)
	    sgngam = -1;
	else
	    sgngam = 1;
	z = q - p;
	if (z > 0.5) {
	    p += 1.0;
	    z = p - q;
	}
	z = q * sin(NPY_PI * z);
	if (z == 0.0)
	    goto lgsing;
	/*     z = log(NPY_PI) - log( z ) - w; */
	z = LOGPI - log(z) - w;
	return (z);
    }

    if (x < 13.0) {
	z = 1.0;
	p = 0.0;
	u = x;
	while (u >= 3.0) {
	    p -= 1.0;
	    u = x + p;
	    z *= u;
	}
	while (u < 2.0) {
	    if (u == 0.0)
		goto lgsing;
	    z /= u;
	    p += 1.0;
	    u = x + p;
	}
	if (z < 0.0) {
	    sgngam = -1;
	    z = -z;
	}
	else
	    sgngam = 1;
	if (u == 2.0)
	    return (log(z));
	p -= 2.0;
	x = x + p;
	p = x * polevl(x, B, 5) / p1evl(x, C, 6);
	return (log(z) + p);
    }

    if (x > MAXLGM) {
	return (sgngam * NPY_INFINITY);
    }

    q = (x - 0.5) * log(x) - x + LS2PI;
    if (x > 1.0e8)
	return (q);

    p = 1.0 / (x * x);
    if (x >= 1000.0)
	q += ((7.9365079365079365079365e-4 * p
	       - 2.7777777777777777777778e-3) * p
	      + 0.0833333333333333333333) / x;
    else
	q += polevl(p, A, 4) / x;
    return (q);
}
Example #6
0
File: gamma.c Project: 317070/scipy
double Gamma(double x)
{
    double p, q, z;
    int i;

    sgngam = 1;
    if (!npy_isfinite(x)) {
	return x;
    }
    q = fabs(x);

    if (q > 33.0) {
	if (x < 0.0) {
	    p = floor(q);
	    if (p == q) {
	      gamnan:
		mtherr("Gamma", OVERFLOW);
		return (NPY_INFINITY);
	    }
	    i = p;
	    if ((i & 1) == 0)
		sgngam = -1;
	    z = q - p;
	    if (z > 0.5) {
		p += 1.0;
		z = q - p;
	    }
	    z = q * sin(NPY_PI * z);
	    if (z == 0.0) {
		return (sgngam * NPY_INFINITY);
	    }
	    z = fabs(z);
	    z = NPY_PI / (z * stirf(q));
	}
	else {
	    z = stirf(x);
	}
	return (sgngam * z);
    }

    z = 1.0;
    while (x >= 3.0) {
	x -= 1.0;
	z *= x;
    }

    while (x < 0.0) {
	if (x > -1.E-9)
	    goto small;
	z /= x;
	x += 1.0;
    }

    while (x < 2.0) {
	if (x < 1.e-9)
	    goto small;
	z /= x;
	x += 1.0;
    }

    if (x == 2.0)
	return (z);

    x -= 2.0;
    p = polevl(x, P, 6);
    q = polevl(x, Q, 7);
    return (z * p / q);

  small:
    if (x == 0.0) {
	goto gamnan;
    }
    else
	return (z / ((1.0 + 0.5772156649015329 * x) * x));
}