#include "mymath.h"

#define EXP(x)	(expf(x))

float
expm1f(float x)
{
    /*
     * (expm1)
     * Return (exp(x) - 1), taking care to avoid subtraction loss.
     *
     * This version uses a [4,4]-degree Padé approximation computed in
     * Maple by
     *
     *     with(numapprox):
     *     Digits := 20:
     *     pade((exp('x') - 1)/'x', 'x' = 0, [4,4]);
     *
     * The coefficients in this approximation are exactly representable.
     * The computed relative error is 6.08e-11, below the IEEE 754
     * machine epsilon of 2**(-23) = 1.19e-07.  This is the lowest
     * degree, and thus optimal, Padé approximation whose error is below
     * that limit.
     * (29-Jun-2002)
     */

    float ret_val;

    /*
     *
     * CUTLO = ln(0.5) (really, ln(1-1/beta) for arbitrary base beta)
     *
     */
    static const float CUTLO = -0.6931471805599453094172321214581765680755001343603F;

    /*
     *
     * CUTHI = ln(1.5) (really, ln(1+1/beta) for arbitrary base beta)
     *
     */
    static const float CUTHI = 0.4054651081081643819780131154643491365719904234625F;

    static const float ONE = 1.0F;
    static const float ZERO = 0.0F;

    /*
     *
     *     We handle the computation in three regions:
     *
     *     x in [-Infinity, CUTLO):  exp(x) - 1
     *     x in [CUTLO, CUTHI]:      Padé approximation
     *     x in (CUTHI, Infinity]:   exp(x) - 1
     *
     *     The central region suffers loss of one or more bits if the
     *     simple formula is used.
     *
     *     The following IF statements handle the case of NaN, signed zero,
     *     and the three regions above.
     *
     */

    if (x != x)				/* then x is a NaN */
	ret_val = x;
    else if (x == ZERO)			/* then x is +0 or -0 */
	ret_val = x;			/* preserve sign of zero */
    else if (x < CUTLO)
	ret_val = EXP(x) - ONE;
    else if (x <= CUTHI)		/* region of accuracy loss from exp(x)-1 */
	ret_val = x * (( 15120.0F + ( 840.0F + ( 420.0F + ( 20.0F + ( 1.0F ) * x) * x) * x) * x) /
		       ( 15120.0F + (-6720.0F + ( 1260.0F + (-120.0F + ( 5.0F ) * x) * x) * x) * x) );
    else
	ret_val = EXP(x) - ONE;

    return (ret_val);
}
