Exemple #1
0
void fpoly_bessel(unsigned int _n, float * _p)
{
    unsigned int k;
    unsigned int N = _n-1;
    for (k=0; k<_n; k++) {
#if 0
        // use internal log(gamma(z))
        float t0 = liquid_lngammaf((float)(2*N-k)+1);
        float t1 = liquid_lngammaf((float)(N-k)  +1);
        float t2 = liquid_lngammaf((float)(k)     +1);
#else
        // use standard math log(gamma(z))
        float t0 = lgammaf((float)(2*N-k)+1);
        float t1 = lgammaf((float)(N-k)  +1);
        float t2 = lgammaf((float)(k)    +1);
#endif

        // M_LN2 = log(2) = 0.693147180559945
        float t3 = M_LN2 * (float)(N-k);    // log(2^(N-k)) = log(2)*log(N-k)

        _p[k] = roundf(expf(t0 - t1 - t2 - t3));

#if 0
        printf("  p[%3u,%3u] = %12.4e\n", k, _n, _p[k]);
        printf("    t0 : %12.4e\n", t0);
        printf("    t1 : %12.4e\n", t1);
        printf("    t2 : %12.4e\n", t2);
        printf("    t3 : %12.4e\n", t3);
#endif
    }
}
Exemple #2
0
float liquid_lngammaf(float _z)
{
    float g;
    if (_z < 0) {
        fprintf(stderr,"error: liquid_lngammaf(), undefined for z <= 0\n");
        exit(1);
    } else if (_z < 10.0f) {
#if 0
        g = -EULER_GAMMA*_z - logf(_z);
        unsigned int k;
        for (k=1; k<NUM_LNGAMMA_ITERATIONS; k++) {
            float t0 = _z / (float)k;
            float t1 = logf(1.0f + t0);

            g += t0 - t1;
        }
#else
        // Use recursive formula:
        //    gamma(z+1) = z * gamma(z)
        // therefore:
        //    log(Gamma(z)) = log(gamma(z+1)) - ln(z)
        return liquid_lngammaf(_z + 1.0f) - logf(_z);
#endif
    } else {
        // high value approximation
        g = 0.5*( logf(2*M_PI)-log(_z) );
        g += _z*( logf(_z+(1/(12.0f*_z-0.1f/_z)))-1);
    }
    return g;
}
Exemple #3
0
float liquid_lnlowergammaf(float _z, float _alpha)
{
    float t0 = _z * logf(_alpha);
    float t1 = liquid_lngammaf(_z);
    float t2 = -_alpha;
    float t3 = 0.0f;

    unsigned int k = 0;
    float log_alpha = logf(_alpha);
    float tprime = 0.0f;
    float tmax = 0.0f;
    float t = 0.0f;
    for (k=0; k<LOWERGAMMA_MAX_ITERATIONS; k++) {
        // retain previous value for t
        tprime = t;

        // compute log( alpha^k / Gamma(_z + k + 1) )
        //         = k*log(alpha) - lnGamma(_z + k + 1)
        t = k*log_alpha - liquid_lngammaf(_z + (float)k + 1.0f);

        // accumulate e^t
        t3 += expf(t);

        // check premature exit criteria
        if (k==0 || t > tmax)
            tmax = t;

        // conditions:
        //  1. minimum number of iterations met
        //  2. surpassed inflection point: k*log(alpha) - log(Gamma(z+k+1))
        //     has an inverted parabolic shape
        //  3. sufficiently beyond peak
        if ( k > LOWERGAMMA_MIN_ITERATIONS && tprime > t && (tmax-t) > 20.0f)
            break;
    }

    return t0 + t1 + t2 + logf(t3);
}
Exemple #4
0
float liquid_gammaf(float _z)
{
    if (_z < 0) {
        // use identities
        //  (1) gamma(z)*gamma(-z) = -pi / (z*sin(pi*z))
        //  (2) z*gamma(z) = gamma(1+z)
        //
        // therefore:
        //  gamma(z) = pi / ( gamma(1-z) * sin(pi*z) )
        float t0 = liquid_gammaf(1.0 - _z);
        float t1 = sinf(M_PI*_z);
        if (t0==0 || t1==0)
            fprintf(stderr,"warning: liquid_gammaf(), divide by zero\n");
        return M_PI / (t0 * t1);
    } else {
        return expf( liquid_lngammaf(_z) );
    }
}
// 
// AUTOTEST: lngamma
//
void autotest_lngamma()
{
    // error tolerance
    float tol = 1e-4f;

    // test vectors
    CONTEND_DELTA( liquid_lngammaf(1.00000000000000e-05), 1.15129196928958e+01, tol );
    CONTEND_DELTA( liquid_lngammaf(1.47910838816821e-05), 1.11214774616959e+01, tol );
    CONTEND_DELTA( liquid_lngammaf(2.18776162394955e-05), 1.07300339056431e+01, tol );
    CONTEND_DELTA( liquid_lngammaf(3.23593656929628e-05), 1.03385883900717e+01, tol );
    CONTEND_DELTA( liquid_lngammaf(4.78630092322638e-05), 9.94713997633970e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(7.07945784384137e-05), 9.55568727630758e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(1.04712854805090e-04), 9.16422823723390e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(1.54881661891248e-04), 8.77275982391398e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(2.29086765276777e-04), 8.38127754918765e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(3.38844156139203e-04), 7.98977478095072e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(5.01187233627273e-04), 7.59824172030200e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(7.41310241300918e-04), 7.20666389700363e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(1.09647819614319e-03), 6.81501995916639e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(1.62181009735893e-03), 6.42327843686104e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(2.39883291901949e-03), 6.03139302698778e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(3.54813389233576e-03), 5.63929577576287e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(5.24807460249773e-03), 5.24688733606614e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(7.76247116628692e-03), 4.85402329836329e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(1.14815362149688e-02), 4.46049557831785e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(1.69824365246175e-02), 4.06600834803635e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(2.51188643150958e-02), 3.67014984368726e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(3.71535229097173e-02), 3.27236635981559e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(5.49540873857625e-02), 2.87195653880158e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(8.12830516164099e-02), 2.46812982675138e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(1.20226443461741e-01), 2.06022544058646e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(1.77827941003892e-01), 1.64828757901128e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(2.63026799189538e-01), 1.23436563201614e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(3.89045144994281e-01), 8.25181176502332e-01, tol );
    CONTEND_DELTA( liquid_lngammaf(5.75439937337158e-01), 4.37193579132034e-01, tol );
    CONTEND_DELTA( liquid_lngammaf(8.51138038202378e-01), 1.05623142071343e-01, tol );
    CONTEND_DELTA( liquid_lngammaf(1.25892541179417e+00),-1.00254418080515e-01, tol );
    CONTEND_DELTA( liquid_lngammaf(1.86208713666287e+00),-5.19895823734552e-02, tol );
    CONTEND_DELTA( liquid_lngammaf(2.75422870333817e+00), 4.78681466346387e-01, tol );
    CONTEND_DELTA( liquid_lngammaf(4.07380277804113e+00), 1.88523210546678e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(6.02559586074358e+00), 4.83122059829788e+00, tol );
    CONTEND_DELTA( liquid_lngammaf(8.91250938133746e+00), 1.04177681572532e+01, tol );
    CONTEND_DELTA( liquid_lngammaf(1.31825673855641e+01), 2.04497048921129e+01, tol );
    CONTEND_DELTA( liquid_lngammaf(1.94984459975805e+01), 3.78565107279246e+01, tol );
    CONTEND_DELTA( liquid_lngammaf(2.88403150312661e+01), 6.73552537656878e+01, tol );
    CONTEND_DELTA( liquid_lngammaf(4.26579518801593e+01), 1.16490742768456e+02, tol );
    CONTEND_DELTA( liquid_lngammaf(6.30957344480194e+01), 1.97262133863497e+02, tol );
    CONTEND_DELTA( liquid_lngammaf(9.33254300796992e+01), 3.28659150940827e+02, tol );
    CONTEND_DELTA( liquid_lngammaf(1.38038426460289e+02), 5.40606126998515e+02, tol );

    // test very large numbers
    CONTEND_DELTA( liquid_lngammaf(140), 550.278651724286, tol);
    CONTEND_DELTA( liquid_lngammaf(150), 600.009470555327, tol);
    CONTEND_DELTA( liquid_lngammaf(160), 650.409682895655, tol);
    CONTEND_DELTA( liquid_lngammaf(170), 701.437263808737, tol);
}