xref: /csrg-svn/lib/libm/common_source/sinh.c (revision 24606)
1*24606Szliu /*
2*24606Szliu  * Copyright (c) 1985 Regents of the University of California.
3*24606Szliu  *
4*24606Szliu  * Use and reproduction of this software are granted  in  accordance  with
5*24606Szliu  * the terms and conditions specified in  the  Berkeley  Software  License
6*24606Szliu  * Agreement (in particular, this entails acknowledgement of the programs'
7*24606Szliu  * source, and inclusion of this notice) with the additional understanding
8*24606Szliu  * that  all  recipients  should regard themselves as participants  in  an
9*24606Szliu  * ongoing  research  project and hence should  feel  obligated  to report
10*24606Szliu  * their  experiences (good or bad) with these elementary function  codes,
11*24606Szliu  * using "sendbug 4bsd-bugs@BERKELEY", to the authors.
12*24606Szliu  */
13*24606Szliu 
14*24606Szliu #ifndef lint
15*24606Szliu static char sccsid[] = "@(#)sinh.c	1.1 (ELEFUNT) 09/06/85";
16*24606Szliu #endif not lint
17*24606Szliu 
18*24606Szliu /* SINH(X)
19*24606Szliu  * RETURN THE HYPERBOLIC SINE OF X
20*24606Szliu  * DOUBLE PRECISION (VAX D format 56 bits, IEEE DOUBLE 53 BITS)
21*24606Szliu  * CODED IN C BY K.C. NG, 1/8/85;
22*24606Szliu  * REVISED BY K.C. NG on 2/8/85, 3/7/85, 3/24/85, 4/16/85.
23*24606Szliu  *
24*24606Szliu  * Required system supported functions :
25*24606Szliu  *	copysign(x,y)
26*24606Szliu  *	scalb(x,N)
27*24606Szliu  *
28*24606Szliu  * Required kernel functions:
29*24606Szliu  *	expm1(x)	...return exp(x)-1
30*24606Szliu  *
31*24606Szliu  * Method :
32*24606Szliu  *	1. reduce x to non-negative by sinh(-x) = - sinh(x).
33*24606Szliu  *	2.
34*24606Szliu  *
35*24606Szliu  *	                                      expm1(x) + expm1(x)/(expm1(x)+1)
36*24606Szliu  *	    0 <= x <= lnovfl     : sinh(x) := --------------------------------
37*24606Szliu  *			       		                      2
38*24606Szliu  *     lnovfl <= x <= lnovfl+ln2 : sinh(x) := expm1(x)/2 (avoid overflow)
39*24606Szliu  * lnovfl+ln2 <  x <  INF        :  overflow to INF
40*24606Szliu  *
41*24606Szliu  *
42*24606Szliu  * Special cases:
43*24606Szliu  *	sinh(x) is x if x is +INF, -INF, or NaN.
44*24606Szliu  *	only sinh(0)=0 is exact for finite argument.
45*24606Szliu  *
46*24606Szliu  * Accuracy:
47*24606Szliu  *	sinh(x) returns the exact hyperbolic sine of x nearly rounded. In
48*24606Szliu  *	a test run with 1,024,000 random arguments on a VAX, the maximum
49*24606Szliu  *	observed error was 1.93 ulps (units in the last place).
50*24606Szliu  *
51*24606Szliu  * Constants:
52*24606Szliu  * The hexadecimal values are the intended ones for the following constants.
53*24606Szliu  * The decimal values may be used, provided that the compiler will convert
54*24606Szliu  * from decimal to binary accurately enough to produce the hexadecimal values
55*24606Szliu  * shown.
56*24606Szliu  */
57*24606Szliu #ifdef VAX
58*24606Szliu /* double static */
59*24606Szliu /* mln2hi =  8.8029691931113054792E1     , Hex  2^  7   *  .B00F33C7E22BDB */
60*24606Szliu /* mln2lo = -4.9650192275318476525E-16   , Hex  2^-50   * -.8F1B60279E582A */
61*24606Szliu /* lnovfl =  8.8029691931113053016E1     ; Hex  2^  7   *  .B00F33C7E22BDA */
62*24606Szliu static long    mln2hix[] = { 0x0f3343b0, 0x2bdbc7e2};
63*24606Szliu static long    mln2lox[] = { 0x1b60a70f, 0x582a279e};
64*24606Szliu static long    lnovflx[] = { 0x0f3343b0, 0x2bdac7e2};
65*24606Szliu #define   mln2hi    (*(double*)mln2hix)
66*24606Szliu #define   mln2lo    (*(double*)mln2lox)
67*24606Szliu #define   lnovfl    (*(double*)lnovflx)
68*24606Szliu #else	/* IEEE double */
69*24606Szliu double static
70*24606Szliu mln2hi =  7.0978271289338397310E2     , /*Hex  2^ 10   *  1.62E42FEFA39EF */
71*24606Szliu mln2lo =  2.3747039373786107478E-14   , /*Hex  2^-45   *  1.ABC9E3B39803F */
72*24606Szliu lnovfl =  7.0978271289338397310E2     ; /*Hex  2^  9   *  1.62E42FEFA39EF */
73*24606Szliu #endif
74*24606Szliu 
75*24606Szliu #ifdef VAX
76*24606Szliu static max = 126                      ;
77*24606Szliu #else	/* IEEE double */
78*24606Szliu static max = 1023                     ;
79*24606Szliu #endif
80*24606Szliu 
81*24606Szliu 
82*24606Szliu double sinh(x)
83*24606Szliu double x;
84*24606Szliu {
85*24606Szliu 	static double  one=1.0, half=1.0/2.0 ;
86*24606Szliu 	double expm1(), t, scalb(), copysign(), sign;
87*24606Szliu #ifndef VAX
88*24606Szliu 	if(x!=x) return(x);	/* x is NaN */
89*24606Szliu #endif
90*24606Szliu 	sign=copysign(one,x);
91*24606Szliu 	x=copysign(x,one);
92*24606Szliu 	if(x<lnovfl)
93*24606Szliu 	    {t=expm1(x); return(copysign((t+t/(one+t))*half,sign));}
94*24606Szliu 
95*24606Szliu 	else if(x <= lnovfl+0.7)
96*24606Szliu 		/* subtract x by ln(2^(max+1)) and return 2^max*exp(x)
97*24606Szliu 	    		to avoid unnecessary overflow */
98*24606Szliu 	    return(copysign(scalb(one+expm1((x-mln2hi)-mln2lo),max),sign));
99*24606Szliu 
100*24606Szliu 	else  /* sinh(+-INF) = +-INF, sinh(+-big no.) overflow to +-INF */
101*24606Szliu 	    return( expm1(x)*sign );
102*24606Szliu }
103