| OLD | NEW |
| (Empty) |
| 1 /* mpfr_sinh_cosh -- hyperbolic sine and cosine | |
| 2 | |
| 3 Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Fou
ndation, Inc. | |
| 4 Contributed by the Arenaire and Cacao projects, INRIA. | |
| 5 | |
| 6 This file is part of the GNU MPFR Library. | |
| 7 | |
| 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 2.1 of the License, or (at your | |
| 11 option) any later version. | |
| 12 | |
| 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. | |
| 17 | |
| 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.LIB. If not, write to | |
| 20 the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, | |
| 21 MA 02110-1301, USA. */ | |
| 22 | |
| 23 #define MPFR_NEED_LONGLONG_H | |
| 24 #include "mpfr-impl.h" | |
| 25 | |
| 26 /* The computations are done by | |
| 27 cosh(x) = 1/2 [e^(x)+e^(-x)] | |
| 28 sinh(x) = 1/2 [e^(x)-e^(-x)] | |
| 29 Adapted from mpfr_sinh.c */ | |
| 30 | |
| 31 int | |
| 32 mpfr_sinh_cosh (mpfr_ptr sh, mpfr_ptr ch, mpfr_srcptr xt, mp_rnd_t rnd_mode) | |
| 33 { | |
| 34 mpfr_t x; | |
| 35 int inexact, inexact_sh, inexact_ch; | |
| 36 | |
| 37 MPFR_ASSERTN (sh != ch); | |
| 38 | |
| 39 MPFR_LOG_FUNC (("x[%#R]=%R rnd=%d", xt, xt, rnd_mode), | |
| 40 ("sh[%#R]=%R ch[%#R]=%R inexact=%d", sh, sh, ch, ch, inexact)); | |
| 41 | |
| 42 if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (xt))) | |
| 43 { | |
| 44 if (MPFR_IS_NAN (xt)) | |
| 45 { | |
| 46 MPFR_SET_NAN (ch); | |
| 47 MPFR_SET_NAN (sh); | |
| 48 MPFR_RET_NAN; | |
| 49 } | |
| 50 else if (MPFR_IS_INF (xt)) | |
| 51 { | |
| 52 MPFR_SET_INF (sh); | |
| 53 MPFR_SET_SAME_SIGN (sh, xt); | |
| 54 MPFR_SET_INF (ch); | |
| 55 MPFR_SET_POS (ch); | |
| 56 MPFR_RET (0); | |
| 57 } | |
| 58 else /* xt is zero */ | |
| 59 { | |
| 60 MPFR_ASSERTD (MPFR_IS_ZERO (xt)); | |
| 61 MPFR_SET_ZERO (sh); /* sinh(0) = 0 */ | |
| 62 MPFR_SET_SAME_SIGN (sh, xt); | |
| 63 return mpfr_set_ui (ch, 1, rnd_mode); /* cosh(0) = 1 */ | |
| 64 } | |
| 65 } | |
| 66 | |
| 67 /* Warning: if we use MPFR_FAST_COMPUTE_IF_SMALL_INPUT here, make sure | |
| 68 that the code also works in case of overlap (see sin_cos.c) */ | |
| 69 | |
| 70 MPFR_TMP_INIT_ABS (x, xt); | |
| 71 | |
| 72 { | |
| 73 mpfr_t s, c, ti; | |
| 74 mp_exp_t d; | |
| 75 mp_prec_t N; /* Precision of the intermediary variables */ | |
| 76 long int err; /* Precision of error */ | |
| 77 MPFR_ZIV_DECL (loop); | |
| 78 MPFR_SAVE_EXPO_DECL (expo); | |
| 79 MPFR_GROUP_DECL (group); | |
| 80 | |
| 81 MPFR_SAVE_EXPO_MARK (expo); | |
| 82 | |
| 83 /* compute the precision of intermediary variable */ | |
| 84 N = MPFR_PREC (ch); | |
| 85 N = MAX (N, MPFR_PREC (sh)); | |
| 86 N = MAX (N, MPFR_PREC (x)); | |
| 87 /* the optimal number of bits : see algorithms.ps */ | |
| 88 N = N + MPFR_INT_CEIL_LOG2 (N) + 4; | |
| 89 | |
| 90 /* initialise of intermediary variables */ | |
| 91 MPFR_GROUP_INIT_3 (group, N, s, c, ti); | |
| 92 | |
| 93 /* First computation of sinh_cosh */ | |
| 94 MPFR_ZIV_INIT (loop, N); | |
| 95 for (;;) | |
| 96 { | |
| 97 MPFR_BLOCK_DECL (flags); | |
| 98 | |
| 99 /* compute sinh_cosh */ | |
| 100 MPFR_BLOCK (flags, mpfr_exp (s, x, GMP_RNDD)); | |
| 101 if (MPFR_OVERFLOW (flags)) | |
| 102 /* exp(x) does overflow */ | |
| 103 { | |
| 104 /* since cosh(x) >= exp(x), cosh(x) overflows too */ | |
| 105 inexact_ch = mpfr_overflow (ch, rnd_mode, MPFR_SIGN_POS); | |
| 106 /* sinh(x) may be representable */ | |
| 107 inexact_sh = mpfr_sinh (sh, xt, rnd_mode); | |
| 108 MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, MPFR_FLAGS_OVERFLOW); | |
| 109 break; | |
| 110 } | |
| 111 d = MPFR_GET_EXP (s); | |
| 112 mpfr_ui_div (ti, 1, s, GMP_RNDU); /* 1/exp(x) */ | |
| 113 mpfr_add (c, s, ti, GMP_RNDU); /* exp(x) + 1/exp(x) */ | |
| 114 mpfr_sub (s, s, ti, GMP_RNDN); /* exp(x) - 1/exp(x) */ | |
| 115 mpfr_div_2ui (c, c, 1, GMP_RNDN); /* 1/2(exp(x) + 1/exp(x)) */ | |
| 116 mpfr_div_2ui (s, s, 1, GMP_RNDN); /* 1/2(exp(x) - 1/exp(x)) */ | |
| 117 | |
| 118 /* it may be that s is zero (in fact, it can only occur when exp(x)=1, | |
| 119 and thus ti=1 too) */ | |
| 120 if (MPFR_IS_ZERO (s)) | |
| 121 err = N; /* double the precision */ | |
| 122 else | |
| 123 { | |
| 124 /* calculation of the error */ | |
| 125 d = d - MPFR_GET_EXP (s) + 2; | |
| 126 /* error estimate: err = N-(__gmpfr_ceil_log2(1+pow(2,d)));*/ | |
| 127 err = N - (MAX (d, 0) + 1); | |
| 128 if (MPFR_LIKELY (MPFR_CAN_ROUND (s, err, MPFR_PREC (sh), | |
| 129 rnd_mode) && \ | |
| 130 MPFR_CAN_ROUND (c, err, MPFR_PREC (ch), | |
| 131 rnd_mode))) | |
| 132 { | |
| 133 inexact_sh = mpfr_set4 (sh, s, rnd_mode, MPFR_SIGN (xt)); | |
| 134 inexact_ch = mpfr_set (ch, c, rnd_mode); | |
| 135 break; | |
| 136 } | |
| 137 } | |
| 138 /* actualisation of the precision */ | |
| 139 N += err; | |
| 140 MPFR_ZIV_NEXT (loop, N); | |
| 141 MPFR_GROUP_REPREC_3 (group, N, s, c, ti); | |
| 142 } | |
| 143 MPFR_ZIV_FREE (loop); | |
| 144 MPFR_GROUP_CLEAR (group); | |
| 145 MPFR_SAVE_EXPO_FREE (expo); | |
| 146 } | |
| 147 | |
| 148 /* now, let's raise the flags if needed */ | |
| 149 inexact = mpfr_check_range (sh, inexact_sh, rnd_mode); | |
| 150 inexact = mpfr_check_range (ch, inexact_ch, rnd_mode) || inexact; | |
| 151 | |
| 152 return inexact; | |
| 153 } | |
| OLD | NEW |