The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/*							atanh.c
 *
 *	Inverse hyperbolic tangent
 *
 *
 *
 * SYNOPSIS:
 *
 * double x, y, atanh();
 *
 * y = atanh( x );
 *
 *
 *
 * DESCRIPTION:
 *
 * Returns inverse hyperbolic tangent of argument in the range
 * MINLOG to MAXLOG.
 *
 * If |x| < 0.5, the rational form x + x**3 P(x)/Q(x) is
 * employed.  Otherwise,
 *        atanh(x) = 0.5 * log( (1+x)/(1-x) ).
 *
 *
 *
 * ACCURACY:
 *
 *                      Relative error:
 * arithmetic   domain     # trials      peak         rms
 *    DEC       -1,1        50000       2.4e-17     6.4e-18
 *    IEEE      -1,1        30000       1.9e-16     5.2e-17
 *
 */

/*						atanh.c	*/


/*
Cephes Math Library Release 2.3:  March, 1995
Copyright (C) 1987, 1995 by Stephen L. Moshier
*/

#include "mconf.h"

static double P[] = {
-8.54074331929669305196E-1,
 1.20426861384072379242E1,
-4.61252884198732692637E1,
 6.54566728676544377376E1,
-3.09092539379866942570E1
};
static double Q[] = {
/* 1.00000000000000000000E0,*/
-1.95638849376911654834E1,
 1.08938092147140262656E2,
-2.49839401325893582852E2,
 2.52006675691344555838E2,
-9.27277618139601130017E1
};
#ifndef ANSIPROT
double fabs(), log(), polevl(), p1evl();
#endif

double atanh(x)
double x;
{
double s, z;

#ifdef MINUSZERO
if( x == 0.0 )
	return(x);
#endif
z = fabs(x);
if( z >= 1.0 )
	{
	if( x == 1.0 )
		return( infinity() );
	if( x == -1.0 )
		return( -infinity() );
	mtherr( "atanh", DOMAIN );
	return( quiet_nan() );
	}

if( z < 1.0e-7 )
	return(x);

if( z < 0.5 )
	{
	z = x * x;
	s = x   +  x * z * (polevl(z, P, 4) / p1evl(z, Q, 5));
	return(s);
	}

return( 0.5 * log((1.0+x)/(1.0-x)) );
}