12116Sjkh/* @(#)s_tanh.c 5.1 93/09/24 */ 22116Sjkh/* 32116Sjkh * ==================================================== 42116Sjkh * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 52116Sjkh * 62116Sjkh * Developed at SunPro, a Sun Microsystems, Inc. business. 72116Sjkh * Permission to use, copy, modify, and distribute this 88870Srgrimes * software is freely granted, provided that this notice 92116Sjkh * is preserved. 102116Sjkh * ==================================================== 112116Sjkh */ 122116Sjkh 13176451Sdas#include <sys/cdefs.h> 14176451Sdas__FBSDID("$FreeBSD$"); 152116Sjkh 162116Sjkh/* Tanh(x) 172116Sjkh * Return the Hyperbolic Tangent of x 182116Sjkh * 192116Sjkh * Method : 202116Sjkh * x -x 212116Sjkh * e - e 222116Sjkh * 0. tanh(x) is defined to be ----------- 232116Sjkh * x -x 242116Sjkh * e + e 252116Sjkh * 1. reduce x to non-negative by tanh(-x) = -tanh(x). 26160122Sbde * 2. 0 <= x < 2**-28 : tanh(x) := x with inexact if x != 0 272116Sjkh * -t 28160122Sbde * 2**-28 <= x < 1 : tanh(x) := -----; t = expm1(-2x) 292116Sjkh * t + 2 302116Sjkh * 2 31160122Sbde * 1 <= x < 22 : tanh(x) := 1 - -----; t = expm1(2x) 322116Sjkh * t + 2 33160122Sbde * 22 <= x <= INF : tanh(x) := 1. 342116Sjkh * 352116Sjkh * Special cases: 362116Sjkh * tanh(NaN) is NaN; 372116Sjkh * only tanh(0)=0 is exact for finite argument. 382116Sjkh */ 392116Sjkh 402116Sjkh#include "math.h" 412116Sjkh#include "math_private.h" 422116Sjkh 43160122Sbdestatic const double one = 1.0, two = 2.0, tiny = 1.0e-300, huge = 1.0e300; 442116Sjkh 4597413Salfreddouble 4697413Salfredtanh(double x) 472116Sjkh{ 482116Sjkh double t,z; 492116Sjkh int32_t jx,ix; 502116Sjkh 512116Sjkh GET_HIGH_WORD(jx,x); 522116Sjkh ix = jx&0x7fffffff; 532116Sjkh 542116Sjkh /* x is INF or NaN */ 558870Srgrimes if(ix>=0x7ff00000) { 562116Sjkh if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */ 572116Sjkh else return one/x-one; /* tanh(NaN) = NaN */ 582116Sjkh } 592116Sjkh 602116Sjkh /* |x| < 22 */ 612116Sjkh if (ix < 0x40360000) { /* |x|<22 */ 62160122Sbde if (ix<0x3e300000) { /* |x|<2**-28 */ 63160122Sbde if(huge+x>one) return x; /* tanh(tiny) = tiny with inexact */ 64160122Sbde } 652116Sjkh if (ix>=0x3ff00000) { /* |x|>=1 */ 662116Sjkh t = expm1(two*fabs(x)); 672116Sjkh z = one - two/(t+two); 682116Sjkh } else { 692116Sjkh t = expm1(-two*fabs(x)); 702116Sjkh z= -t/(t+two); 712116Sjkh } 72160122Sbde /* |x| >= 22, return +-1 */ 732116Sjkh } else { 74160122Sbde z = one - tiny; /* raise inexact flag */ 752116Sjkh } 762116Sjkh return (jx>=0)? z: -z; 772116Sjkh} 78