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 40a48e1f22SSteve Kargl #include <float.h> 41a48e1f22SSteve Kargl 423a8617a8SJordan K. Hubbard #include "math.h" 433a8617a8SJordan K. Hubbard #include "math_private.h" 443a8617a8SJordan K. Hubbard 45*79c2e69aSSteve Kargl static volatile const double tiny = 1.0e-300; 46*79c2e69aSSteve Kargl static const double one = 1.0, two = 2.0, huge = 1.0e300; 473a8617a8SJordan K. Hubbard 4859b19ff1SAlfred Perlstein double 4959b19ff1SAlfred Perlstein tanh(double x) 503a8617a8SJordan K. Hubbard { 513a8617a8SJordan K. Hubbard double t,z; 523a8617a8SJordan K. Hubbard int32_t jx,ix; 533a8617a8SJordan K. Hubbard 543a8617a8SJordan K. Hubbard GET_HIGH_WORD(jx,x); 553a8617a8SJordan K. Hubbard ix = jx&0x7fffffff; 563a8617a8SJordan K. Hubbard 573a8617a8SJordan K. Hubbard /* x is INF or NaN */ 583a8617a8SJordan K. Hubbard if(ix>=0x7ff00000) { 593a8617a8SJordan K. Hubbard if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */ 603a8617a8SJordan K. Hubbard else return one/x-one; /* tanh(NaN) = NaN */ 613a8617a8SJordan K. Hubbard } 623a8617a8SJordan K. Hubbard 633a8617a8SJordan K. Hubbard /* |x| < 22 */ 643a8617a8SJordan K. Hubbard if (ix < 0x40360000) { /* |x|<22 */ 65fe72622eSBruce Evans if (ix<0x3e300000) { /* |x|<2**-28 */ 66fe72622eSBruce Evans if(huge+x>one) return x; /* tanh(tiny) = tiny with inexact */ 67fe72622eSBruce Evans } 683a8617a8SJordan K. Hubbard if (ix>=0x3ff00000) { /* |x|>=1 */ 693a8617a8SJordan K. Hubbard t = expm1(two*fabs(x)); 703a8617a8SJordan K. Hubbard z = one - two/(t+two); 713a8617a8SJordan K. Hubbard } else { 723a8617a8SJordan K. Hubbard t = expm1(-two*fabs(x)); 733a8617a8SJordan K. Hubbard z= -t/(t+two); 743a8617a8SJordan K. Hubbard } 75fe72622eSBruce Evans /* |x| >= 22, return +-1 */ 763a8617a8SJordan K. Hubbard } else { 77fe72622eSBruce Evans z = one - tiny; /* raise inexact flag */ 783a8617a8SJordan K. Hubbard } 793a8617a8SJordan K. Hubbard return (jx>=0)? z: -z; 803a8617a8SJordan K. Hubbard } 81a48e1f22SSteve Kargl 82a48e1f22SSteve Kargl #if (LDBL_MANT_DIG == 53) 83a48e1f22SSteve Kargl __weak_reference(tanh, tanhl); 84a48e1f22SSteve Kargl #endif 85