1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  28  * Use is subject to license terms.
  29  */
  30 
  31 #pragma weak __sinhl = sinhl
  32 
  33 #include "libm.h"
  34 #include "longdouble.h"
  35 
  36 /*
  37  * sinhl(X)
  38  * RETURN THE HYPERBOLIC SINE OF X
  39  *
  40  * Method :
  41  *      1. reduce x to non-negative by sinhl(-x) = - sinhl(x).
  42  *      2.
  43  *
  44  *                                           expm1l(x) + expm1l(x)/(expm1l(x)+1)
  45  *      0 <= x <= lnovft  : sinhl(x) := --------------------------------
  46  *                                                           2
  47  *
  48  *     lnovft <= x <  INF : sinhl(x) := expl(x-MEP1*ln2)*2**ME
  49  *
  50  * here
  51  *      lnovft:         logrithm of the overflow threshold
  52  *                      = MEP1*ln2 chopped to machine precision.
  53  *      ME              maximum exponent
  54  *      MEP1            maximum exponent plus 1
  55  *
  56  * Special cases:
  57  *      sinhl(x) is x if x is +INF, -INF, or NaN.
  58  *      only sinhl(0)=0 is exact for finite argument.
  59  *
  60  */
  61 
  62 #define ME              16383
  63 #define MEP1            16384
  64 #define LNOVFT          1.135652340629414394949193107797076342845e+4L
  65 /* last 32 bits of LN2HI is zero */
  66 #define LN2HI           6.931471805599453094172319547495844850203e-0001L
  67 #define LN2LO           1.667085920830552208890449330400379754169e-0025L
  68 
  69 static const long double half = 0.5L,
  70         one = 1.0L,
  71         ln2hi = LN2HI,
  72         ln2lo = LN2LO,
  73         lnovftL = LNOVFT;
  74 
  75 long double
  76 sinhl(long double x)
  77 {
  78         long double r, t;
  79 
  80         if (!finitel(x))
  81                 return (x + x);         /* sinh of NaN or +-INF is itself */
  82 
  83         r = fabsl(x);
  84 
  85         if (r < lnovftL) {
  86                 t = expm1l(r);
  87                 r = copysignl((t + t / (one + t)) * half, x);
  88         } else {
  89                 r = copysignl(expl((r - MEP1 * ln2hi) - MEP1 * ln2lo), x);
  90                 r = scalbnl(r, ME);
  91         }
  92 
  93         return (r);
  94 }