13a8617a8SJordan K. Hubbard /* @(#)s_tanh.c 5.1 93/09/24 */ 23a8617a8SJordan K. Hubbard /* 33a8617a8SJordan K. Hubbard * ==================================================== 43a8617a8SJordan K. Hubbard * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 53a8617a8SJordan K. Hubbard * 63a8617a8SJordan K. Hubbard * Developed at SunPro, a Sun Microsystems, Inc. business. 73a8617a8SJordan K. Hubbard * Permission to use, copy, modify, and distribute this 83a8617a8SJordan K. Hubbard * software is freely granted, provided that this notice 93a8617a8SJordan K. Hubbard * is preserved. 103a8617a8SJordan K. Hubbard * ==================================================== 113a8617a8SJordan K. Hubbard */ 123a8617a8SJordan K. Hubbard 135aa554c7SDavid Schultz #include <sys/cdefs.h> 145aa554c7SDavid Schultz __FBSDID("$FreeBSD$"); 153a8617a8SJordan K. Hubbard 163a8617a8SJordan K. Hubbard /* Tanh(x) 173a8617a8SJordan K. Hubbard * Return the Hyperbolic Tangent of x 183a8617a8SJordan K. Hubbard * 193a8617a8SJordan K. Hubbard * Method : 203a8617a8SJordan K. Hubbard * x -x 213a8617a8SJordan K. Hubbard * e - e 223a8617a8SJordan K. Hubbard * 0. tanh(x) is defined to be ----------- 233a8617a8SJordan K. Hubbard * x -x 243a8617a8SJordan K. Hubbard * e + e 253a8617a8SJordan K. Hubbard * 1. reduce x to non-negative by tanh(-x) = -tanh(x). 26fe72622eSBruce Evans * 2. 0 <= x < 2**-28 : tanh(x) := x with inexact if x != 0 273a8617a8SJordan K. Hubbard * -t 28fe72622eSBruce Evans * 2**-28 <= x < 1 : tanh(x) := -----; t = expm1(-2x) 293a8617a8SJordan K. Hubbard * t + 2 303a8617a8SJordan K. Hubbard * 2 31fe72622eSBruce Evans * 1 <= x < 22 : tanh(x) := 1 - -----; t = expm1(2x) 323a8617a8SJordan K. Hubbard * t + 2 33fe72622eSBruce Evans * 22 <= x <= INF : tanh(x) := 1. 343a8617a8SJordan K. Hubbard * 353a8617a8SJordan K. Hubbard * Special cases: 363a8617a8SJordan K. Hubbard * tanh(NaN) is NaN; 373a8617a8SJordan K. Hubbard * only tanh(0)=0 is exact for finite argument. 383a8617a8SJordan K. Hubbard */ 393a8617a8SJordan K. Hubbard 40*a48e1f22SSteve Kargl #include <float.h> 41*a48e1f22SSteve Kargl 423a8617a8SJordan K. Hubbard #include "math.h" 433a8617a8SJordan K. Hubbard #include "math_private.h" 443a8617a8SJordan K. Hubbard 45fe72622eSBruce Evans static const double one = 1.0, two = 2.0, tiny = 1.0e-300, huge = 1.0e300; 463a8617a8SJordan K. Hubbard 4759b19ff1SAlfred Perlstein double 4859b19ff1SAlfred Perlstein tanh(double x) 493a8617a8SJordan K. Hubbard { 503a8617a8SJordan K. Hubbard double t,z; 513a8617a8SJordan K. Hubbard int32_t jx,ix; 523a8617a8SJordan K. Hubbard 533a8617a8SJordan K. Hubbard GET_HIGH_WORD(jx,x); 543a8617a8SJordan K. Hubbard ix = jx&0x7fffffff; 553a8617a8SJordan K. Hubbard 563a8617a8SJordan K. Hubbard /* x is INF or NaN */ 573a8617a8SJordan K. Hubbard if(ix>=0x7ff00000) { 583a8617a8SJordan K. Hubbard if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */ 593a8617a8SJordan K. Hubbard else return one/x-one; /* tanh(NaN) = NaN */ 603a8617a8SJordan K. Hubbard } 613a8617a8SJordan K. Hubbard 623a8617a8SJordan K. Hubbard /* |x| < 22 */ 633a8617a8SJordan K. Hubbard if (ix < 0x40360000) { /* |x|<22 */ 64fe72622eSBruce Evans if (ix<0x3e300000) { /* |x|<2**-28 */ 65fe72622eSBruce Evans if(huge+x>one) return x; /* tanh(tiny) = tiny with inexact */ 66fe72622eSBruce Evans } 673a8617a8SJordan K. Hubbard if (ix>=0x3ff00000) { /* |x|>=1 */ 683a8617a8SJordan K. Hubbard t = expm1(two*fabs(x)); 693a8617a8SJordan K. Hubbard z = one - two/(t+two); 703a8617a8SJordan K. Hubbard } else { 713a8617a8SJordan K. Hubbard t = expm1(-two*fabs(x)); 723a8617a8SJordan K. Hubbard z= -t/(t+two); 733a8617a8SJordan K. Hubbard } 74fe72622eSBruce Evans /* |x| >= 22, return +-1 */ 753a8617a8SJordan K. Hubbard } else { 76fe72622eSBruce Evans z = one - tiny; /* raise inexact flag */ 773a8617a8SJordan K. Hubbard } 783a8617a8SJordan K. Hubbard return (jx>=0)? z: -z; 793a8617a8SJordan K. Hubbard } 80*a48e1f22SSteve Kargl 81*a48e1f22SSteve Kargl #if (LDBL_MANT_DIG == 53) 82*a48e1f22SSteve Kargl __weak_reference(tanh, tanhl); 83*a48e1f22SSteve Kargl #endif 84