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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  27  * Use is subject to license terms.
  28  */
  29 
  30 #pragma weak __sinhl = sinhl
  31 
  32 #include "libm.h"
  33 #include "longdouble.h"
  34 
  35 /*
  36  * sinhl(X)
  37  * RETURN THE HYPERBOLIC SINE OF X
  38  *
  39  * Method :
  40  *      1. reduce x to non-negative by sinhl(-x) = - sinhl(x).
  41  *      2.
  42  *
  43  *                                           expm1l(x) + expm1l(x)/(expm1l(x)+1)
  44  *      0 <= x <= lnovft  : sinhl(x) := --------------------------------
  45  *                                                           2
  46  *
  47  *     lnovft <= x <  INF : sinhl(x) := expl(x-MEP1*ln2)*2**ME
  48  *
  49  * here
  50  *      lnovft:         logrithm of the overflow threshold
  51  *                      = MEP1*ln2 chopped to machine precision.
  52  *      ME              maximum exponent
  53  *      MEP1            maximum exponent plus 1
  54  *
  55  * Special cases:
  56  *      sinhl(x) is x if x is +INF, -INF, or NaN.
  57  *      only sinhl(0)=0 is exact for finite argument.
  58  *
  59  */
  60 
  61 #define ME      16383
  62 #define MEP1    16384
  63 #define LNOVFT  1.135652340629414394949193107797076342845e+4L
  64                 /* last 32 bits of LN2HI is zero */
  65 #define LN2HI   6.931471805599453094172319547495844850203e-0001L
  66 #define LN2LO   1.667085920830552208890449330400379754169e-0025L
  67 
  68 static const long double
  69         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         long double r, t;
  78 
  79         if (!finitel(x))
  80                 return (x + x); /* sinh of NaN or +-INF is itself */
  81         r = fabsl(x);
  82         if (r < lnovftL) {
  83                 t = expm1l(r);
  84                 r = copysignl((t + t / (one + t)) * half, x);
  85         } else {
  86                 r = copysignl(expl((r - MEP1 * ln2hi) - MEP1 * ln2lo), x);
  87                 r = scalbnl(r, ME);
  88         }
  89         return (r);
  90 }