#include "mymath.h"

#define EXP(x)	(exp(x))

double
expm1(double x)
{
    /*
     * (expm1)
     * Return (exp(x) - 1), taking care to avoid subtraction loss.
     * (11-Jun-2002)
     */

    double ret_val,
        sum,
        term,
        xn;

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

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

    static const double ONE = 1.0;
    static const double ZERO = 0.0;

    /*
     *
     *     We handle the computation in three regions:
     *
     *     x in [-Infinity, CUTLO):  exp(x) - 1
     *     x in [CUTLO, CUTHI]:      Taylor series
     *     x in (CUTHI, Infinity]:   exp(x) - 1
     *
     *     The central region suffers loss of one or more bits if the
     *     simple formula is used.
     *
     *     The number of terms in the Taylor series depends on the value of
     *     x, and the arithmetic system: these values are for IEEE 754
     *     arithmetic:
     *
     *                 =========================================
     *                             Taylor series terms needed
     *                 x         32-bit  64-bit  80-bit  128-bit
     *                 =========================================
     *                 CUTLO      10      17      19       29
     *                 CUTLO/2     8      14      16       24
     *                 0           1       1       1        1
     *                 0.001       4       6       7       11
     *                 0.01        4       7       9       13
     *                 0.1         6      11      12       19
     *                 CUTHI/2     7      12      14       22
     *                 CUTHI       8      14      16       25
     *                 =========================================
     *
     *     By using the argument reduction formula
     *
     *         expm1(x) = (exp(x) - 1)
     *                   = (exp(x/2)*exp(x/2) - 1)
     *                   = (expm1(x/2)+1)^2 - 1)
     *                   = expm1(x/2)^2 + 2*expm1(x/2)
     *
     *     we can compute the Taylor series for x/2, then recover expm1(x)
     *     with two multiplies and two adds.  Each Taylor series term costs
     *     one add, one multiply, and one divide, and the above table
     *     suggests that halving x saves two Taylor series terms.  The
     *     reduction formula therefore saves two divides, which is
     *     substantial.  However, this reduction should be done ONLY on
     *     base-2 floating-point systems; on IBM S/390 base-16 systems,
     *     division by 2 loses one bit.
     *
     *     The following IF statements handle the case of NaN, signed zero,
     *     and the three regions above.  If NaN comparisons are botched or
     *     incorrectly optimized away, code should fall through to the ELSE
     *     part, which will generate a NaN provided that exp(NaN) returns a
     *     NaN.  If NaN's comparisons are badly botched, then we might get
     *     into a loop that never terminates: therefore, validation testing
     *     is imperative!
     *
     */

    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 */
    {
	term = x;
	sum = ZERO;
	xn = ONE;
	while ((sum + term) != sum)	/* Taylor series summation */
	{
	    sum = sum + term;
	    xn = xn + ONE;
	    term = term * x / xn;
	}
	ret_val = sum;
    }
    else
	ret_val = EXP(x) - ONE;

    return (ret_val);
}
