summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4>2020-12-16 10:02:47 +0000
committerzimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4>2020-12-16 10:02:47 +0000
commit85ddb25cb0d6c08210e3bee519db9d599d3d3ffe (patch)
tree65464dd6ff10f2b134ca81bb9718e4fba870761d
parentb487cf60a5bacd76d0ad465972a9092e01cfe9e5 (diff)
downloadmpfr-85ddb25cb0d6c08210e3bee519db9d599d3d3ffe.tar.gz
added new function mpfr_tanu
git-svn-id: https://scm.gforge.inria.fr/anonscm/svn/mpfr/trunk@14210 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r--NEWS2
-rw-r--r--doc/mpfr.texi8
-rw-r--r--src/Makefile.am2
-rw-r--r--src/mpfr.h1
-rw-r--r--src/tanu.c177
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/ttanu.c218
7 files changed, 404 insertions, 6 deletions
diff --git a/NEWS b/NEWS
index e9862fbda..8cd0d629a 100644
--- a/NEWS
+++ b/NEWS
@@ -22,7 +22,7 @@ https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
Changes from versions 4.1.* to version 4.2.0:
- The "" release.
-- New functions mpfr_cosu and mpfr_sinu (experimental).
+- New functions mpfr_cosu, mpfr_sinu and mpfr_tanu (experimental).
- Bug fixes.
In particular, for the formatted output functions (mpfr_printf, etc.),
the case where the precision consists only of a period has been fixed
diff --git a/doc/mpfr.texi b/doc/mpfr.texi
index afe2a25f9..0afd01568 100644
--- a/doc/mpfr.texi
+++ b/doc/mpfr.texi
@@ -2269,9 +2269,10 @@ tangent of @var{op}, rounded in the direction @var{rnd}.
@deftypefun int mpfr_cosu (mpfr_t @var{rop}, mpfr_t @var{op}, unsigned long @var{u}, mpfr_rnd_t @var{rnd})
@deftypefunx int mpfr_sinu (mpfr_t @var{rop}, mpfr_t @var{op}, unsigned long @var{u}, mpfr_rnd_t @var{rnd})
-Set @var{rop} to the cosine (resp. sine) of @m{@var{op} \times 2\pi/u,@var{op} multiplied
-by 2@tie{}Pi and divided by @var{u}}. Thus if @var{u} equals 360, one
-gets the cosine (resp. sine) for @var{op} in degrees.
+@deftypefunx int mpfr_tanu (mpfr_t @var{rop}, mpfr_t @var{op}, unsigned long @var{u}, mpfr_rnd_t @var{rnd})
+Set @var{rop} to the cosine (resp. sine and tangent) of @m{@var{op} \times 2\pi/u,@var{op} multiplied
+by 2@tie{}Pi and divided by @var{u}}. For example, if @var{u} equals 360, one
+gets the cosine (resp. sine and tangent) for @var{op} in degrees.
For @code{mpfr_cosu},
when @m{@var{op} \times 2/u,@var{op}
multiplied by 2 and divided by @var{u}} is a half-integer, the result is +0,
@@ -2282,6 +2283,7 @@ when @m{@var{op} \times 2/u,@var{op}
multiplied by 2 and divided by @var{u}} is an integer, the result is zero
with the same sign as @var{op}, following IEEE@tie{}754-2019 (sinPi),
so that the function is odd.
+Similarly, the function @code{mpfr_tanu} follows IEEE@tie{}754-2019 (tanPi).
Note: these functions are experimental and their interface might change in future
versions.
diff --git a/src/Makefile.am b/src/Makefile.am
index 10686c5f7..c1cd06a4b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -67,7 +67,7 @@ grandom.c fpif.c set_float128.c get_float128.c rndna.c nrandom.c \
random_deviate.h random_deviate.c erandom.c mpfr-mini-gmp.c \
mpfr-mini-gmp.h fmma.c log_ui.c gamma_inc.c ubf.c invert_limb.h \
invsqrt_limb.h beta.c odd_p.c get_q.c pool.c total_order.c set_d128.c \
-get_d128.c nbits_ulong.c cmpabs_ui.c sinu.c cosu.c
+get_d128.c nbits_ulong.c cmpabs_ui.c sinu.c cosu.c tanu.c
nodist_libmpfr_la_SOURCES = $(BUILT_SOURCES)
diff --git a/src/mpfr.h b/src/mpfr.h
index 74d6c675a..ed63df92f 100644
--- a/src/mpfr.h
+++ b/src/mpfr.h
@@ -723,6 +723,7 @@ __MPFR_DECLSPEC int mpfr_cot (mpfr_ptr, mpfr_srcptr, mpfr_rnd_t);
__MPFR_DECLSPEC int mpfr_sinu (mpfr_ptr, mpfr_srcptr, unsigned long, mpfr_rnd_t);
__MPFR_DECLSPEC int mpfr_cosu (mpfr_ptr, mpfr_srcptr, unsigned long, mpfr_rnd_t);
+__MPFR_DECLSPEC int mpfr_tanu (mpfr_ptr, mpfr_srcptr, unsigned long, mpfr_rnd_t);
__MPFR_DECLSPEC int mpfr_hypot (mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mpfr_rnd_t);
__MPFR_DECLSPEC int mpfr_erf (mpfr_ptr, mpfr_srcptr, mpfr_rnd_t);
diff --git a/src/tanu.c b/src/tanu.c
new file mode 100644
index 000000000..1d9710a8b
--- /dev/null
+++ b/src/tanu.c
@@ -0,0 +1,177 @@
+/* mpfr_tanu -- tanu(x) = tan(2*pi*x/u)
+
+Copyright 2020 Free Software Foundation, Inc.
+Contributed by the AriC and Caramba projects, INRIA.
+
+This file is part of the GNU MPFR Library.
+
+The GNU MPFR Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+The GNU MPFR Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
+https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#define MPFR_NEED_LONGLONG_H
+#include "mpfr-impl.h"
+
+/* FIXME[VL]: Implement the range reduction in this function.
+ That's the whole point of tanu compared to tan. */
+
+/* put in y the corrected-rounded value of tan(2*pi*x/u) */
+int
+mpfr_tanu (mpfr_ptr y, mpfr_srcptr x, unsigned long u, mpfr_rnd_t rnd_mode)
+{
+ mpfr_prec_t precy, prec;
+ mpfr_exp_t expx, expt, err;
+ mpfr_t t;
+ int inexact = 0, nloops = 0, underflow = 0;
+ MPFR_ZIV_DECL (loop);
+ MPFR_SAVE_EXPO_DECL (expo);
+
+ MPFR_LOG_FUNC (
+ ("x[%Pu]=%*.Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode),
+ ("y[%Pu]=%*.Rg inexact=%d", mpfr_get_prec (y), mpfr_log_prec, y,
+ inexact));
+
+ if (u == 0 || MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
+ {
+ /* for u=0, return NaN */
+ if (u == 0 || MPFR_IS_NAN (x) || MPFR_IS_INF (x))
+ {
+ MPFR_SET_NAN (y);
+ MPFR_RET_NAN;
+ }
+ else /* x is zero */
+ {
+ MPFR_ASSERTD (MPFR_IS_ZERO (x));
+ MPFR_SET_ZERO (y);
+ MPFR_SET_SAME_SIGN (y, x);
+ MPFR_RET (0);
+ }
+ }
+
+ MPFR_SAVE_EXPO_MARK (expo);
+
+ precy = MPFR_PREC (y);
+ expx = MPFR_GET_EXP (x);
+ /* for x large, since argument reduction is expensive, we want to avoid
+ any failure in Ziv's strategy, thus we take into account expx too */
+ prec = precy + MPFR_INT_CEIL_LOG2 (MAX(precy,expx)) + 8;
+ MPFR_ASSERTD(prec >= 2);
+ mpfr_init2 (t, prec);
+ MPFR_ZIV_INIT (loop, prec);
+ for (;;)
+ {
+ int inex;
+ nloops ++;
+ /* We first compute an approximation t of 2*pi*x/u, then call tan(t).
+ If t = 2*pi*x/u + s, then
+ |tan(t) - tan(2*pi*x/u)| = |s| * (1 + tan(v)^2) where v is in the
+ interval [t, t+s]. If we ensure that |t| >= |2*pi*x/u|, since tan() is
+ increasing, we can bound tan(v)^2 by tan(t)^2. */
+ mpfr_set_prec (t, prec);
+ mpfr_const_pi (t, MPFR_RNDU); /* t = pi * (1 + theta1) where
+ |theta1| <= 2^(1-prec) */
+ mpfr_mul_2ui (t, t, 1, MPFR_RNDN); /* t = 2*pi * (1 + theta1) */
+ mpfr_mul (t, t, x, MPFR_RNDA); /* t = 2*pi*x * (1 + theta2)^2 where
+ |theta2| <= 2^(1-prec) */
+ inex = mpfr_div_ui (t, t, u, MPFR_RNDN);
+ /* t = 2*pi*x/u * (1 + theta3)^3 where |theta3| <= 2^(1-prec) */
+ /* if t is zero here, it means the division by u underflows, then
+ tan(t) also underflows, since |tan(x)| <= |x|. */
+ if (MPFR_UNLIKELY (MPFR_IS_ZERO (t)))
+ {
+ inexact = mpfr_underflow (y, rnd_mode, MPFR_SIGN(t));
+ MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, MPFR_FLAGS_INEXACT
+ | MPFR_FLAGS_UNDERFLOW);
+ underflow = 1;
+ goto end;
+ }
+ /* emulate mpfr_div_ui (t, t, u, MPFR_RNDA) above, so that t is rounded
+ away from zero */
+ if (MPFR_SIGN(t) > 0 && inex < 0)
+ mpfr_nextabove (t);
+ else if (MPFR_SIGN(t) < 0 && inex > 0)
+ mpfr_nextbelow (t);
+ expt = MPFR_GET_EXP (t);
+ /* since prec >= 3, |(1 + theta3)^3 - 1| <= 4*theta3 <= 2^(3-prec)
+ thus |s| = |t - 2*pi*x/u| <= |t| * 2^(3-prec) */
+ mpfr_tan (t, t, MPFR_RNDA);
+ {
+ /* compute an upper bound for 1+tan(t)^2 */
+ mpfr_t z;
+ mpfr_init2 (z, 64);
+ mpfr_sqr (z, t, MPFR_RNDU);
+ mpfr_add_ui (z, z, 1, MPFR_RNDU);
+ expt += MPFR_GET_EXP (z);
+ /* now |t - tan(2*pi*x/u)| <= ulp(t) + 2^(expt + 3 - prec) */
+ mpfr_clear (z);
+ }
+ /* t cannot be zero here, since we excluded t=0 before, which is the
+ only exact case where tan(t)=0, and we round away from zero */
+ err = expt + 3 - prec;
+ expt = MPFR_GET_EXP (t); /* new exponent of t */
+ /* the total error is bounded by 2^err + ulp(t) = 2^err + 2^(expt-prec)
+ thus if err <= expt-prec, it is bounded by 2^(expt-prec+1),
+ otherwise it is bounded by 2^(err+1). */
+ err = (err <= expt - prec) ? expt - prec + 1 : err + 1;
+ /* normalize err for mpfr_can_round */
+ err = expt - err;
+ if (MPFR_CAN_ROUND (t, err, precy, rnd_mode))
+ break;
+ /* Check exact cases only after the first level of Ziv' strategy, to
+ avoid slowing down the average case. Exact cases are when 2*pi*x/u
+ is a multiple of pi/4, i.e., x/u a multiple of 1/8:
+ (a) x/u = {0,1/2} mod 1: return +0 or -0
+ (b) x/u = {1/4,3/4} mod 1: return +Inf or -Inf
+ (c) x/u = {1/8,3/8,5/8,7/8} mod 1: return 1 or -1 */
+ if (nloops == 1)
+ {
+ inexact = mpfr_div_ui (t, x, u, MPFR_RNDA);
+ mpfr_mul_2ui (t, t, 3, MPFR_RNDA);
+ if (inexact == 0 && mpfr_integer_p (t))
+ {
+ mpz_t z;
+ unsigned long mod8;
+ mpz_init (z);
+ inexact = mpfr_get_z (z, t, MPFR_RNDZ);
+ MPFR_ASSERTN(inexact == 0);
+ mod8 = mpz_fdiv_ui (z, 8);
+ mpz_clear (z);
+ if (mod8 == 0 || mod8 == 4) /* case (a) */
+ mpfr_set_zero (y, ((mod8 == 0) ? +1 : -1) * MPFR_SIGN (x));
+ else if (mod8 == 2 || mod8 == 6) /* case (b) */
+ {
+ mpfr_set_inf (y, (mod8 == 2) ? +1 : -1);
+ MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, MPFR_FLAGS_DIVBY0);
+ }
+ else /* case (c) */
+ {
+ if (mod8 == 1 || mod8 == 5)
+ mpfr_set_ui (y, 1, rnd_mode);
+ else
+ mpfr_set_si (y, -1, rnd_mode);
+ }
+ goto end;
+ }
+ }
+ MPFR_ZIV_NEXT (loop, prec);
+ }
+ MPFR_ZIV_FREE (loop);
+
+ inexact = mpfr_set (y, t, rnd_mode);
+
+ end:
+ mpfr_clear (t);
+ MPFR_SAVE_EXPO_FREE (expo);
+ return underflow ? inexact : mpfr_check_range (y, inexact, rnd_mode);
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 190caaf13..2a4f16fa0 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -50,7 +50,7 @@ TESTS_NO_TVERSION = tabort_prec_max tassert tabort_defalloc1 \
tset_str tset_z tset_z_2exp tsi_op tsin tsin_cos tsinh tsinh_cosh \
tsinu tsprintf tsqr tsqrt tsqrt_ui tstckintc tstdint tstrtofr \
tsub tsub1sp tsub_d tsub_ui tsubnormal tsum tswap ttan ttanh \
- ttotal_order ttrunc tui_div tui_pow tui_sub turandom tvalist \
+ ttanu ttotal_order ttrunc tui_div tui_pow tui_sub turandom tvalist \
ty0 ty1 tyn tzeta tzeta_ui
check_PROGRAMS = tversion $(TESTS_NO_TVERSION)
diff --git a/tests/ttanu.c b/tests/ttanu.c
new file mode 100644
index 000000000..9933a0a26
--- /dev/null
+++ b/tests/ttanu.c
@@ -0,0 +1,218 @@
+/* Test file for mpfr_tanu.
+
+Copyright 2020 Free Software Foundation, Inc.
+Contributed by the AriC and Caramba projects, INRIA.
+
+This file is part of the GNU MPFR Library.
+
+The GNU MPFR Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+The GNU MPFR Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
+https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include "mpfr-test.h"
+
+static void
+test_singular (void)
+{
+ mpfr_t x, y;
+ int inexact;
+
+ mpfr_init (x);
+ mpfr_init (y);
+
+ /* check u = 0 */
+ mpfr_set_ui (x, 17, MPFR_RNDN);
+ inexact = mpfr_tanu (y, x, 0, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_nan_p (y));
+
+ /* check x = NaN */
+ mpfr_set_nan (x);
+ inexact = mpfr_tanu (y, x, 1, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_nan_p (y));
+
+ /* check x = +Inf */
+ mpfr_set_inf (x, 1);
+ inexact = mpfr_tanu (y, x, 1, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_nan_p (y));
+
+ /* check x = -Inf */
+ mpfr_set_inf (x, -1);
+ inexact = mpfr_tanu (y, x, 1, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_nan_p (y));
+
+ /* check x = +0 */
+ mpfr_set_zero (x, 1);
+ inexact = mpfr_tanu (y, x, 1, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_zero_p (y) && mpfr_signbit (y) == 0);
+ MPFR_ASSERTN(inexact == 0);
+
+ /* check x = -0 */
+ mpfr_set_zero (x, -1);
+ inexact = mpfr_tanu (y, x, 1, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_zero_p (y) && mpfr_signbit (y) != 0);
+ MPFR_ASSERTN(inexact == 0);
+
+ mpfr_clear (x);
+ mpfr_clear (y);
+}
+
+static void
+test_exact (void)
+{
+ mpfr_t x, y;
+ int inexact;
+
+ mpfr_init2 (x, 6);
+ mpfr_init2 (y, 6);
+
+ /* check n + 0.5 for n integer */
+ for (int n = 0; n < 10; n++)
+ {
+ /* check 2n+0.5 for n>=0: +Inf and divide by 0 exception */
+ mpfr_set_ui (x, 4 * n + 1, MPFR_RNDN);
+ mpfr_clear_divby0 ();
+ inexact = mpfr_tanu (y, x, 4, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_inf_p (y) && mpfr_sgn (y) > 0);
+ MPFR_ASSERTN(inexact == 0);
+ MPFR_ASSERTN(mpfr_divby0_p ());
+
+ /* check 2n+1 for n>=0: -0 */
+ mpfr_set_ui (x, 4 * n + 2, MPFR_RNDN);
+ mpfr_clear_divby0 ();
+ inexact = mpfr_tanu (y, x, 4, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_zero_p (y) && mpfr_signbit (y) != 0);
+ MPFR_ASSERTN(inexact == 0);
+ MPFR_ASSERTN(!mpfr_divby0_p ());
+
+ /* check 2n+1.5 for n>=0: -Inf and divide by 0 exception */
+ mpfr_set_ui (x, 4 * n + 3, MPFR_RNDN);
+ mpfr_clear_divby0 ();
+ inexact = mpfr_tanu (y, x, 4, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_inf_p (y) && mpfr_sgn (y) < 0);
+ MPFR_ASSERTN(inexact == 0);
+ MPFR_ASSERTN(mpfr_divby0_p ());
+
+ /* check 2n+2 for n>=0: +0 */
+ mpfr_set_ui (x, 4 * n + 4, MPFR_RNDN);
+ mpfr_clear_divby0 ();
+ inexact = mpfr_tanu (y, x, 4, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_zero_p (y) && mpfr_signbit (y) == 0);
+ MPFR_ASSERTN(inexact == 0);
+ MPFR_ASSERTN(!mpfr_divby0_p ());
+
+ /* check -2n-0.5 for n>=0: -Inf and divide by 0 exception */
+ mpfr_set_si (x, -4 * n - 1, MPFR_RNDN);
+ mpfr_clear_divby0 ();
+ inexact = mpfr_tanu (y, x, 4, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_inf_p (y) && mpfr_sgn (y) < 0);
+ MPFR_ASSERTN(inexact == 0);
+ MPFR_ASSERTN(mpfr_divby0_p ());
+
+ /* check -2n-1 for n>=0: +0 */
+ mpfr_set_si (x, -4 * n - 2, MPFR_RNDN);
+ mpfr_clear_divby0 ();
+ inexact = mpfr_tanu (y, x, 4, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_zero_p (y) && mpfr_signbit (y) == 0);
+ MPFR_ASSERTN(inexact == 0);
+ MPFR_ASSERTN(!mpfr_divby0_p ());
+
+ /* check -2n-1.5 for n>=0: +Inf and divide by 0 exception */
+ mpfr_set_si (x, -4 * n - 3, MPFR_RNDN);
+ mpfr_clear_divby0 ();
+ inexact = mpfr_tanu (y, x, 4, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_inf_p (y) && mpfr_sgn (y) > 0);
+ MPFR_ASSERTN(inexact == 0);
+ MPFR_ASSERTN(mpfr_divby0_p ());
+
+ /* check -2n-2 for n>=0: -0 */
+ mpfr_set_si (x, -4 * n - 4, MPFR_RNDN);
+ mpfr_clear_divby0 ();
+ inexact = mpfr_tanu (y, x, 4, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_zero_p (y) && mpfr_signbit (y) != 0);
+ MPFR_ASSERTN(inexact == 0);
+ MPFR_ASSERTN(!mpfr_divby0_p ());
+ }
+
+ /* check 2*pi*x/u = pi/4 thus x/u = 1/8, for example x=1 and u=8 */
+ mpfr_set_ui (x, 1, MPFR_RNDN);
+ inexact = mpfr_tanu (y, x, 8, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_cmp_ui (y, 1) == 0 && inexact == 0);
+
+ /* check 2*pi*x/u = 3*pi/4 thus x/u = 3/8, for example x=3 and u=8 */
+ mpfr_set_ui (x, 3, MPFR_RNDN);
+ inexact = mpfr_tanu (y, x, 8, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_cmp_si (y, -1) == 0 && inexact == 0);
+
+ /* check 2*pi*x/u = 5*pi/4 thus x/u = 5/8, for example x=5 and u=8 */
+ mpfr_set_ui (x, 5, MPFR_RNDN);
+ inexact = mpfr_tanu (y, x, 8, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_cmp_ui (y, 1) == 0 && inexact == 0);
+
+ /* check 2*pi*x/u = 7*pi/4 thus x/u = 7/8, for example x=7 and u=8 */
+ mpfr_set_ui (x, 7, MPFR_RNDN);
+ inexact = mpfr_tanu (y, x, 8, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_cmp_si (y, -1) == 0 && inexact == 0);
+
+ mpfr_clear (x);
+ mpfr_clear (y);
+}
+
+static void
+test_regular (void)
+{
+ mpfr_t x, y, z;
+ int inexact;
+
+ mpfr_init2 (x, 53);
+ mpfr_init2 (y, 53);
+ mpfr_init2 (z, 53);
+
+ mpfr_set_ui (x, 17, MPFR_RNDN);
+ inexact = mpfr_tanu (y, x, 42, MPFR_RNDN);
+ /* y should be tan(2*17*pi/42) rounded to nearest */
+ mpfr_set_str (z, "-0xa.e89b03074638p-4", 16, MPFR_RNDN);
+ MPFR_ASSERTN(mpfr_equal_p (y, z));
+ MPFR_ASSERTN(inexact > 0);
+
+ mpfr_clear (x);
+ mpfr_clear (y);
+ mpfr_clear (z);
+}
+
+/* FIXME[VL]: For mpfr_tanu, the range reduction should not be expensive.
+ If I'm not mistaken, this is linear in the bitsize of the exponent
+ since one just needs to compute the argument modulo the integer u. */
+#define TEST_FUNCTION mpfr_tanu
+#define ULONG_ARG2
+#ifndef MPFR_USE_MINI_GMP
+#define REDUCE_EMAX 262143 /* otherwise arg. reduction is too expensive */
+#else
+#define REDUCE_EMAX 16383 /* reduce further since mini-gmp works in O(n^2) */
+#endif
+#include "tgeneric.c"
+
+int
+main (void)
+{
+ tests_start_mpfr ();
+
+ test_singular ();
+ test_exact ();
+ test_regular ();
+
+ test_generic (MPFR_PREC_MIN, 100, 1);
+
+ tests_end_mpfr ();
+ return 0;
+}