/* -*-C-*- atan.c */

/*
	floating-point arctangent

	atan returns the value of the arctangent of its
	argument in the range [-pi/2,pi/2].

	atan2 returns the arctangent of arg1/arg2
	in the range [-pi,pi].

	there are no error returns.

	coefficients are #5077 from Hart & Cheney. (19.56D)
*/

#include "elefunt.h"

static dp_t satan ARGS((dp_t arg));
static dp_t xatan ARGS((dp_t arg));

static dp_t sq2p1 = 2.414213562373095048802e0;
static dp_t sq2m1 =.414213562373095048802e0;
static dp_t pio2 = 1.570796326794896619231e0;
static dp_t pio4 =.785398163397448309615e0;
static dp_t p4 =.161536412982230228262e2;
static dp_t p3 =.26842548195503973794141e3;
static dp_t p2 =.11530293515404850115428136e4;
static dp_t p1 =.178040631643319697105464587e4;
static dp_t p0 =.89678597403663861959987488e3;
static dp_t q4 =.5895697050844462222791e2;
static dp_t q3 =.536265374031215315104235e3;
static dp_t q2 =.16667838148816337184521798e4;
static dp_t q1 =.207933497444540981287275926e4;
static dp_t q0 =.89678597403663861962481162e3;


/*
	atan makes its argument positive and
	calls the inner routine satan.
*/

#if STDC
dp_t
atan(dp_t arg)
#else /* NOT STDC */
dp_t
atan(arg)
dp_t arg;
#endif /* STDC */
{
    if (arg > 0)
	return (satan(arg));
    else
	return (-satan(-arg));
}


/*
	atan2 discovers what quadrant the angle
	is in and calls atan.
*/

#if STDC
dp_t
atan2(dp_t arg1, dp_t arg2)
#else /* NOT STDC */
dp_t
atan2(arg1, arg2)
dp_t arg1,
    arg2;
#endif /* STDC */
{
    if ((arg1 + arg2) == arg1)
	if (arg1 >= 0.)
	    return (pio2);
	else
	    return (-pio2);
    else
    if (arg2 < 0.)
	if (arg1 >= 0.)
	    return (pio2 + pio2 - satan(-arg1 / arg2));
	else
	    return (-pio2 - pio2 + satan(arg1 / arg2));
    else
    if (arg1 > 0)
	return (satan(arg1 / arg2));
    else
	return (-satan(-arg1 / arg2));
}

/*
	satan reduces its argument (known to be positive)
	to the range [0,0.414...] and calls xatan.
*/

#if STDC
static dp_t
satan(dp_t arg)
#else /* NOT STDC */
static dp_t
satan(arg)
dp_t arg;
#endif /* STDC */
{
    if (arg < sq2m1)
	return (xatan(arg));
    else
    if (arg > sq2p1)
	return (pio2 - xatan(1.0 / arg));
    else
	return (pio4 + xatan((arg - 1.0) / (arg + 1.0)));
}

/*
	xatan evaluates a series valid in the
	range [-0.414...,+0.414...].
*/

#if STDC
static dp_t
xatan(dp_t arg)
#else /* NOT STDC */
static dp_t
xatan(arg)
dp_t arg;
#endif /* STDC */
{
    dp_t argsq;
    dp_t value;

    argsq = arg * arg;
    value = ((((p4 * argsq + p3) * argsq + p2) * argsq + p1) * argsq + p0);
    value = value / (((((argsq + q4) * argsq + q3) * argsq + q2) * argsq + q1) * argsq + q0);
    return (value * arg);
}
