summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coth.c14
-rw-r--r--csch.c10
-rw-r--r--gen_inverse.h19
-rw-r--r--tests/tcoth.c28
-rw-r--r--tests/tcsch.c16
-rw-r--r--tests/tsech.c16
6 files changed, 97 insertions, 6 deletions
diff --git a/coth.c b/coth.c
index 889ef5790..4ecc52d1a 100644
--- a/coth.c
+++ b/coth.c
@@ -34,4 +34,18 @@ MA 02110-1301, USA. */
#define ACTION_ZERO(y,x) do { MPFR_SET_SAME_SIGN(y,x); MPFR_SET_ZERO(y); \
MPFR_RET(0); } while (1)
+/* We know |coth(x)| > 1, thus if the approximation z is such that
+ 1 <= z <= 1 + 2^(-p) where p is the target precision, then the
+ result is either 1 or nextabove(1) = 1 + 2^(1-p). */
+#define ACTION_SPECIAL \
+ if (MPFR_GET_EXP(z) == 1) /* 1 <= |z| < 2 */ \
+ { \
+ mpfr_sub_ui (z, z, MPFR_SIGN(z) > 0 ? 1 : -1, GMP_RNDN); \
+ if (MPFR_IS_ZERO(z) || MPFR_GET_EXP(z) <= - (mp_exp_t) precy) \
+ { \
+ mpfr_add_ui (z, z, MPFR_SIGN(z) > 0 ? 1 : -1, GMP_RNDN); \
+ break; \
+ } \
+ }
+
#include "gen_inverse.h"
diff --git a/csch.c b/csch.c
index e90bb0765..2129753b2 100644
--- a/csch.c
+++ b/csch.c
@@ -20,11 +20,11 @@ the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
MA 02110-1301, USA. */
/* the hyperbolic cosecant is defined by csch(x) = 1/sinh(x).
- csc (NaN) = NaN.
- csc (+Inf) = 0+.
- csc (-Inf) = 0-.
- csc (+0) = +Inf.
- csc (-0) = -Inf.
+ csch (NaN) = NaN.
+ csch (+Inf) = +0.
+ csch (-Inf) = -0.
+ csch (+0) = +Inf.
+ csch (-0) = -Inf.
*/
#define FUNCTION mpfr_csch
diff --git a/gen_inverse.h b/gen_inverse.h
index d2a69d8e7..b4f23a305 100644
--- a/gen_inverse.h
+++ b/gen_inverse.h
@@ -22,6 +22,10 @@ MA 02110-1301, USA. */
#define MPFR_NEED_LONGLONG_H
#include "mpfr-impl.h"
+#ifndef ACTION_SPECIAL
+#define ACTION_SPECIAL
+#endif
+
/* example of use:
#define FUNCTION mpfr_sec
#define INVERSE mpfr_cos
@@ -60,13 +64,26 @@ FUNCTION (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode)
MPFR_ZIV_INIT (loop, m);
for(;;)
{
- INVERSE (z, x, GMP_RNDZ); /* error k_u < 1 ulp */
+ INVERSE (z, x, GMP_RNDZ); /* error k_u < 1 ulp */
+ /* the following assumes that if an overflow happens with
+ MPFR_EMAX_MAX, then necessarily an underflow happens with
+ __gmpfr_emin */
+ if (mpfr_overflow_p ())
+ {
+ int s = MPFR_SIGN(z);
+ MPFR_ZIV_FREE (loop);
+ mpfr_clear (z);
+ MPFR_SAVE_EXPO_FREE (expo);
+ return mpfr_underflow (y, (rnd_mode == GMP_RNDN) ?
+ GMP_RNDZ : rnd_mode, s);
+ }
mpfr_ui_div (z, 1, z, GMP_RNDN);
/* the error is less than c_w + 2*c_u*k_u (see algorithms.tex),
where c_w = 1/2, c_u = 1 since z was rounded towards zero,
thus 1/2 + 2 < 4 */
if (MPFR_LIKELY (MPFR_CAN_ROUND (z, m - 2, precy, rnd_mode)))
break;
+ ACTION_SPECIAL;
MPFR_ZIV_NEXT (loop, m);
mpfr_set_prec (z, m);
}
diff --git a/tests/tcoth.c b/tests/tcoth.c
index 94605256d..1fef81189 100644
--- a/tests/tcoth.c
+++ b/tests/tcoth.c
@@ -98,6 +98,34 @@ check_bugs (void)
exit (1);
}
+ mpfr_set_prec (x, 53);
+ mpfr_set_prec (y, 53);
+
+ mpfr_set_str (x, "18.368400284838550", 10, GMP_RNDN);
+ mpfr_set_str (y, "1.0000000000000002", 10, GMP_RNDN);
+ mpfr_coth (x, x, GMP_RNDN);
+ if (mpfr_cmp (x, y) != 0)
+ {
+ printf ("Error for coth(18.368400284838550)\n");
+ exit (1);
+ }
+
+ mpfr_set_str (x, "18.714973875118520", 10, GMP_RNDN);
+ mpfr_coth (x, x, GMP_RNDN);
+ if (mpfr_cmp (x, y) != 0)
+ {
+ printf ("Error for coth(18.714973875118520)\n");
+ exit (1);
+ }
+
+ mpfr_set_str (x, "18.714973875118524", 10, GMP_RNDN);
+ mpfr_coth (x, x, GMP_RNDN);
+ if (mpfr_cmp_ui (x, 1) != 0)
+ {
+ printf ("Error for coth(18.714973875118524)\n");
+ exit (1);
+ }
+
mpfr_clear (x);
mpfr_clear (y);
}
diff --git a/tests/tcsch.c b/tests/tcsch.c
index 172625488..271666518 100644
--- a/tests/tcsch.c
+++ b/tests/tcsch.c
@@ -75,6 +75,22 @@ check_specials (void)
exit (1);
}
+ /* check huge x */
+ mpfr_set_str (x, "8e8", 10, GMP_RNDN);
+ mpfr_csch (y, x, GMP_RNDN);
+ if (! (mpfr_zero_p (y) && MPFR_SIGN (y) > 0))
+ {
+ printf ("Error: csch(8e8) != +0\n");
+ exit (1);
+ }
+ mpfr_set_str (x, "-8e8", 10, GMP_RNDN);
+ mpfr_csch (y, x, GMP_RNDN);
+ if (! (mpfr_zero_p (y) && MPFR_SIGN (y) < 0))
+ {
+ printf ("Error: csch(-8e8) != -0\n");
+ exit (1);
+ }
+
mpfr_clear (x);
mpfr_clear (y);
}
diff --git a/tests/tsech.c b/tests/tsech.c
index 3a585763e..623def916 100644
--- a/tests/tsech.c
+++ b/tests/tsech.c
@@ -75,6 +75,22 @@ check_specials (void)
exit (1);
}
+ /* check huge x */
+ mpfr_set_str (x, "8e8", 10, GMP_RNDN);
+ mpfr_sech (y, x, GMP_RNDN);
+ if (! (mpfr_zero_p (y) && MPFR_SIGN (y) > 0))
+ {
+ printf ("Error: sech(8e8) != +0\n");
+ exit (1);
+ }
+ mpfr_set_str (x, "-8e8", 10, GMP_RNDN);
+ mpfr_sech (y, x, GMP_RNDN);
+ if (! (mpfr_zero_p (y) && MPFR_SIGN (y) > 0))
+ {
+ printf ("Error: sech(-8e8) != +0\n");
+ exit (1);
+ }
+
mpfr_clear (x);
mpfr_clear (y);
}