11590Srgrimes/* @(#)s_asinh.c 5.1 93/09/24 */
21590Srgrimes/*
31590Srgrimes * ====================================================
41590Srgrimes * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
51590Srgrimes *
61590Srgrimes * Developed at SunPro, a Sun Microsystems, Inc. business.
71590Srgrimes * Permission to use, copy, modify, and distribute this
81590Srgrimes * software is freely granted, provided that this notice
91590Srgrimes * is preserved.
101590Srgrimes * ====================================================
111590Srgrimes */
121590Srgrimes
131590Srgrimes#include <sys/cdefs.h>
141590Srgrimes__FBSDID("$FreeBSD$");
151590Srgrimes
161590Srgrimes/* asinh(x)
171590Srgrimes * Method :
181590Srgrimes *	Based on
191590Srgrimes *		asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
201590Srgrimes *	we have
211590Srgrimes *	asinh(x) := x  if  1+x*x=1,
221590Srgrimes *		 := sign(x)*(log(x)+ln2)) for large |x|, else
231590Srgrimes *		 := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
241590Srgrimes *		 := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
251590Srgrimes */
261590Srgrimes
271590Srgrimes#include <float.h>
281590Srgrimes
2950477Speter#include "math.h"
301590Srgrimes#include "math_private.h"
311590Srgrimes
321590Srgrimesstatic const double
331590Srgrimesone =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
341590Srgrimesln2 =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
351590Srgrimeshuge=  1.00000000000000000000e+300;
361590Srgrimes
371590Srgrimesdouble
3884303Sruasinh(double x)
391590Srgrimes{
401590Srgrimes	double t,w;
411590Srgrimes	int32_t hx,ix;
421590Srgrimes	GET_HIGH_WORD(hx,x);
431590Srgrimes	ix = hx&0x7fffffff;
441590Srgrimes	if(ix>=0x7ff00000) return x+x;	/* x is inf or NaN */
451590Srgrimes	if(ix< 0x3e300000) {	/* |x|<2**-28 */
461590Srgrimes	    if(huge+x>one) return x;	/* return x inexact except 0 */
471590Srgrimes	}
481590Srgrimes	if(ix>0x41b00000) {	/* |x| > 2**28 */
491590Srgrimes	    w = __ieee754_log(fabs(x))+ln2;
501590Srgrimes	} else if (ix>0x40000000) {	/* 2**28 > |x| > 2.0 */
511590Srgrimes	    t = fabs(x);
521590Srgrimes	    w = __ieee754_log(2.0*t+one/(__ieee754_sqrt(x*x+one)+t));
531590Srgrimes	} else {		/* 2.0 > |x| > 2**-28 */
541590Srgrimes	    t = x*x;
551590Srgrimes	    w =log1p(fabs(x)+t/(one+__ieee754_sqrt(one+t)));
561590Srgrimes	}
571590Srgrimes	if(hx>0) return w; else return -w;
581590Srgrimes}
591590Srgrimes
601590Srgrimes#if LDBL_MANT_DIG == 53
611590Srgrimes__weak_reference(asinh, asinhl);
621590Srgrimes#endif
631590Srgrimes