1 /* mpfr_tanh -- hyperbolic tangent
3 Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
4 Contributed by the AriC and Caramel projects, INRIA.
6 This file is part of the GNU MPFR Library.
8 The GNU MPFR Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
13 The GNU MPFR Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
20 http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
23 #define MPFR_NEED_LONGLONG_H
24 #include "mpfr-impl.h"
27 mpfr_tanh (mpfr_ptr y
, mpfr_srcptr xt
, mpfr_rnd_t rnd_mode
)
29 /****** Declaration ******/
32 MPFR_SAVE_EXPO_DECL (expo
);
35 (("x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (xt
), mpfr_log_prec
, xt
, rnd_mode
),
36 ("y[%Pu]=%.*Rg inexact=%d",
37 mpfr_get_prec (y
), mpfr_log_prec
, y
, inexact
));
39 /* Special value checking */
40 if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (xt
)))
47 else if (MPFR_IS_INF (xt
))
49 /* tanh(inf) = 1 && tanh(-inf) = -1 */
50 return mpfr_set_si (y
, MPFR_INT_SIGN (xt
), rnd_mode
);
52 else /* tanh (0) = 0 and xt is zero */
54 MPFR_ASSERTD (MPFR_IS_ZERO(xt
));
56 MPFR_SET_SAME_SIGN (y
, xt
);
61 /* tanh(x) = x - x^3/3 + ... so the error is < 2^(3*EXP(x)-1) */
62 MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y
, xt
, -2 * MPFR_GET_EXP (xt
), 1, 0,
65 MPFR_TMP_INIT_ABS (x
, xt
);
67 MPFR_SAVE_EXPO_MARK (expo
);
71 /* Declaration of the intermediary variable */
75 /* Declaration of the size variable */
76 mpfr_prec_t Ny
= MPFR_PREC(y
); /* target precision */
77 mpfr_prec_t Nt
; /* working precision */
78 long int err
; /* error */
79 int sign
= MPFR_SIGN (xt
);
81 MPFR_GROUP_DECL (group
);
83 /* First check for BIG overflow of exp(2*x):
84 For x > 0, exp(2*x) > 2^(2*x)
85 If 2 ^(2*x) > 2^emax or x>emax/2, there is an overflow */
86 if (MPFR_UNLIKELY (mpfr_cmp_si (x
, __gmpfr_emax
/2) >= 0)) {
87 /* initialise of intermediary variables
88 since 'set_one' label assumes the variables have been
90 MPFR_GROUP_INIT_2 (group
, MPFR_PREC_MIN
, t
, te
);
94 /* Compute the precision of intermediary variable */
95 /* The optimal number of bits: see algorithms.tex */
96 Nt
= Ny
+ MPFR_INT_CEIL_LOG2 (Ny
) + 4;
97 /* if x is small, there will be a cancellation in exp(2x)-1 */
98 if (MPFR_GET_EXP (x
) < 0)
99 Nt
+= -MPFR_GET_EXP (x
);
101 /* initialise of intermediary variable */
102 MPFR_GROUP_INIT_2 (group
, Nt
, t
, te
);
104 MPFR_ZIV_INIT (loop
, Nt
);
106 /* tanh = (exp(2x)-1)/(exp(2x)+1) */
107 mpfr_mul_2ui (te
, x
, 1, MPFR_RNDN
); /* 2x */
108 /* since x > 0, we can only have an overflow */
109 mpfr_exp (te
, te
, MPFR_RNDN
); /* exp(2x) */
110 if (MPFR_UNLIKELY (MPFR_IS_INF (te
))) {
112 inexact
= MPFR_FROM_SIGN_TO_INT (sign
);
113 mpfr_set4 (y
, __gmpfr_one
, MPFR_RNDN
, sign
);
114 if (MPFR_IS_LIKE_RNDZ (rnd_mode
, MPFR_IS_NEG_SIGN (sign
)))
121 d
= MPFR_GET_EXP (te
); /* For Error calculation */
122 mpfr_add_ui (t
, te
, 1, MPFR_RNDD
); /* exp(2x) + 1*/
123 mpfr_sub_ui (te
, te
, 1, MPFR_RNDU
); /* exp(2x) - 1*/
124 d
= d
- MPFR_GET_EXP (te
);
125 mpfr_div (t
, te
, t
, MPFR_RNDN
); /* (exp(2x)-1)/(exp(2x)+1)*/
127 /* Calculation of the error */
131 if (MPFR_LIKELY ((d
<= Nt
/ 2) && MPFR_CAN_ROUND (t
, err
, Ny
, rnd_mode
)))
133 inexact
= mpfr_set4 (y
, t
, rnd_mode
, sign
);
137 /* if t=1, we still can round since |sinh(x)| < 1 */
138 if (MPFR_GET_EXP (t
) == 1)
141 /* Actualisation of the precision */
142 MPFR_ZIV_NEXT (loop
, Nt
);
143 MPFR_GROUP_REPREC_2 (group
, Nt
, t
, te
);
145 MPFR_ZIV_FREE (loop
);
146 MPFR_GROUP_CLEAR (group
);
148 MPFR_SAVE_EXPO_FREE (expo
);
149 inexact
= mpfr_check_range (y
, inexact
, rnd_mode
);