(root)/
mpfr-4.2.1/
src/
tanu.c
       1  /* mpfr_tanu  -- tanu(x) = tan(2*pi*x/u)
       2     mpfr_tanpi -- tanpi(x) = tan(pi*x)
       3  
       4  Copyright 2020-2023 Free Software Foundation, Inc.
       5  Contributed by the AriC and Caramba projects, INRIA.
       6  
       7  This file is part of the GNU MPFR Library.
       8  
       9  The GNU MPFR Library is free software; you can redistribute it and/or modify
      10  it under the terms of the GNU Lesser General Public License as published by
      11  the Free Software Foundation; either version 3 of the License, or (at your
      12  option) any later version.
      13  
      14  The GNU MPFR Library is distributed in the hope that it will be useful, but
      15  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      16  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
      17  License for more details.
      18  
      19  You should have received a copy of the GNU Lesser General Public License
      20  along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
      21  https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
      22  51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
      23  
      24  #define MPFR_NEED_LONGLONG_H
      25  #include "mpfr-impl.h"
      26  
      27  /* put in y the correctly rounded value of tan(2*pi*x/u) */
      28  int
      29  mpfr_tanu (mpfr_ptr y, mpfr_srcptr x, unsigned long u, mpfr_rnd_t rnd_mode)
      30  {
      31    mpfr_srcptr xp;
      32    mpfr_prec_t precy, prec;
      33    mpfr_exp_t expx, expt, err;
      34    mpfr_t t, xr;
      35    int inexact = 0, nloops = 0, underflow = 0;
      36    MPFR_ZIV_DECL (loop);
      37    MPFR_SAVE_EXPO_DECL (expo);
      38  
      39    MPFR_LOG_FUNC (
      40      ("x[%Pd]=%.*Rg u=%lu rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, u,
      41       rnd_mode),
      42      ("y[%Pd]=%.*Rg inexact=%d", mpfr_get_prec (y), mpfr_log_prec, y,
      43       inexact));
      44  
      45    if (u == 0 || MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
      46      {
      47        /* for u=0, return NaN */
      48        if (u == 0 || MPFR_IS_NAN (x) || MPFR_IS_INF (x))
      49          {
      50            MPFR_SET_NAN (y);
      51            MPFR_RET_NAN;
      52          }
      53        else /* x is zero */
      54          {
      55            MPFR_ASSERTD (MPFR_IS_ZERO (x));
      56            MPFR_SET_ZERO (y);
      57            MPFR_SET_SAME_SIGN (y, x);
      58            MPFR_RET (0);
      59          }
      60      }
      61  
      62    MPFR_SAVE_EXPO_MARK (expo);
      63  
      64    /* Range reduction. We do not need to reduce the argument if it is
      65       already reduced (|x| < u).
      66       Note that the case |x| = u is better in the "else" branch as it
      67       will give xr = 0. */
      68    if (mpfr_cmpabs_ui (x, u) < 0)
      69      {
      70        xp = x;
      71      }
      72    else
      73      {
      74        mpfr_exp_t p = MPFR_GET_PREC (x) - MPFR_GET_EXP (x);
      75        int inex;
      76  
      77        /* Let's compute xr = x mod u, with signbit(xr) = signbit(x), which
      78           may be important when x is a multiple of u, in which case xr = 0
      79           (but this property is actually not needed in the code below).
      80           The precision of xr is chosen to ensure that x mod u is exactly
      81           representable in xr, e.g., the maximum size of u + the length of
      82           the fractional part of x. Note that since |x| >= u in this branch,
      83           the additional memory amount will not be more than the one of x.
      84           Note that due to the rules on the special values, we needed to
      85           consider a period of u instead of u/2. */
      86        mpfr_init2 (xr, sizeof (unsigned long) * CHAR_BIT + (p < 0 ? 0 : p));
      87        MPFR_DBGRES (inex = mpfr_fmod_ui (xr, x, u, MPFR_RNDN));  /* exact */
      88        MPFR_ASSERTD (inex == 0);
      89        if (MPFR_IS_ZERO (xr))
      90          {
      91            mpfr_clear (xr);
      92            MPFR_SAVE_EXPO_FREE (expo);
      93            MPFR_SET_ZERO (y);
      94            MPFR_SET_SAME_SIGN (y, x);
      95            MPFR_RET (0);
      96          }
      97        xp = xr;
      98      }
      99  
     100    /* now |xp/u| < 1 */
     101  
     102    precy = MPFR_GET_PREC (y);
     103    expx = MPFR_GET_EXP (xp);
     104    /* For x large, since argument reduction is expensive, we want to avoid
     105       any failure in Ziv's strategy, thus we take into account expx too. */
     106    prec = precy + MAX(expx,MPFR_INT_CEIL_LOG2(precy)) + 8;
     107    MPFR_ASSERTD(prec >= 2);
     108    mpfr_init2 (t, prec);
     109    MPFR_ZIV_INIT (loop, prec);
     110    for (;;)
     111      {
     112        int inex;
     113        nloops ++;
     114        /* In the error analysis below, xp stands for x.
     115           We first compute an approximation t of 2*pi*x/u, then call tan(t).
     116           If t = 2*pi*x/u + s, then
     117           |tan(t) - tan(2*pi*x/u)| = |s| * (1 + tan(v)^2) where v is in the
     118           interval [t, t+s]. If we ensure that |t| >= |2*pi*x/u|, since tan() is
     119           increasing, we can bound tan(v)^2 by tan(t)^2. */
     120        mpfr_set_prec (t, prec);
     121        mpfr_const_pi (t, MPFR_RNDU); /* t = pi * (1 + theta1) where
     122                                         |theta1| <= 2^(1-prec) */
     123        mpfr_mul_2ui (t, t, 1, MPFR_RNDN); /* t = 2*pi * (1 + theta1) */
     124        mpfr_mul (t, t, xp, MPFR_RNDA);    /* t = 2*pi*x * (1 + theta2)^2 where
     125                                              |theta2| <= 2^(1-prec) */
     126        inex = mpfr_div_ui (t, t, u, MPFR_RNDN);
     127        /* t = 2*pi*x/u * (1 + theta3)^3 where |theta3| <= 2^(1-prec) */
     128        /* if t is zero here, it means the division by u underflows, then
     129           tan(t) also underflows, since |tan(x)| <= |x|. */
     130        if (MPFR_UNLIKELY (MPFR_IS_ZERO (t)))
     131          {
     132            inexact = mpfr_underflow (y, rnd_mode, MPFR_SIGN(t));
     133            MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, MPFR_FLAGS_INEXACT
     134                                         | MPFR_FLAGS_UNDERFLOW);
     135            underflow = 1;
     136            goto end;
     137          }
     138        /* emulate mpfr_div_ui (t, t, u, MPFR_RNDA) above, so that t is rounded
     139           away from zero */
     140        if (MPFR_SIGN(t) > 0 && inex < 0)
     141          mpfr_nextabove (t);
     142        else if (MPFR_SIGN(t) < 0 && inex > 0)
     143          mpfr_nextbelow (t);
     144        expt = MPFR_GET_EXP (t);
     145        /* since prec >= 3, |(1 + theta3)^3 - 1| <= 4*theta3 <= 2^(3-prec)
     146           thus |s| = |t - 2*pi*x/u| <= |t| * 2^(3-prec) */
     147        mpfr_tan (t, t, MPFR_RNDA);
     148        {
     149          /* compute an upper bound for 1+tan(t)^2 */
     150          mpfr_t z;
     151          mpfr_init2 (z, 64);
     152          mpfr_sqr (z, t, MPFR_RNDU);
     153          mpfr_add_ui (z, z, 1, MPFR_RNDU);
     154          expt += MPFR_GET_EXP (z);
     155          /* now |t - tan(2*pi*x/u)| <= ulp(t) + 2^(expt + 3 - prec) */
     156          mpfr_clear (z);
     157        }
     158        /* t cannot be zero here, since we excluded t=0 before, which is the
     159           only exact case where tan(t)=0, and we round away from zero */
     160        err = expt + 3 - prec;
     161        expt = MPFR_GET_EXP (t); /* new exponent of t */
     162        /* the total error is bounded by 2^err + ulp(t) = 2^err + 2^(expt-prec)
     163           thus if err <= expt-prec, it is bounded by 2^(expt-prec+1),
     164           otherwise it is bounded by 2^(err+1). */
     165        err = (err <= expt - prec) ? expt - prec + 1 : err + 1;
     166        /* normalize err for mpfr_can_round */
     167        err = expt - err;
     168        if (MPFR_CAN_ROUND (t, err, precy, rnd_mode))
     169          break;
     170        /* Check exact cases only after the first level of Ziv' strategy, to
     171           avoid slowing down the average case. Exact cases are when 2*pi*x/u
     172           is a multiple of pi/4, i.e., x/u a multiple of 1/8:
     173           (a) x/u = {0,1/2} mod 1: return +0 or -0
     174           (b) x/u = {1/4,3/4} mod 1: return +Inf or -Inf
     175           (c) x/u = {1/8,3/8,5/8,7/8} mod 1: return 1 or -1 */
     176        if (nloops == 1)
     177          {
     178            inexact = mpfr_div_ui (t, xp, u, MPFR_RNDA);
     179            mpfr_mul_2ui (t, t, 3, MPFR_RNDA);
     180            if (inexact == 0 && mpfr_integer_p (t))
     181              {
     182                mpz_t z;
     183                unsigned long mod8;
     184                mpz_init (z);
     185                inexact = mpfr_get_z (z, t, MPFR_RNDZ);
     186                MPFR_ASSERTN(inexact == 0);
     187                mod8 = mpz_fdiv_ui (z, 8);
     188                mpz_clear (z);
     189                if (mod8 == 0 || mod8 == 4) /* case (a) */
     190                  mpfr_set_zero (y, ((mod8 == 0) ? +1 : -1) * MPFR_SIGN (x));
     191                else if (mod8 == 2 || mod8 == 6) /* case (b) */
     192                  {
     193                    mpfr_set_inf (y, (mod8 == 2) ? +1 : -1);
     194                    MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, MPFR_FLAGS_DIVBY0);
     195                  }
     196                else /* case (c) */
     197                  {
     198                    if (mod8 == 1 || mod8 == 5)
     199                      mpfr_set_ui (y, 1, rnd_mode);
     200                    else
     201                      mpfr_set_si (y, -1, rnd_mode);
     202                  }
     203                goto end;
     204              }
     205          }
     206        MPFR_ZIV_NEXT (loop, prec);
     207      }
     208    MPFR_ZIV_FREE (loop);
     209  
     210    inexact = mpfr_set (y, t, rnd_mode);
     211  
     212   end:
     213    mpfr_clear (t);
     214    if (xp != x)
     215      {
     216        MPFR_ASSERTD (xp == xr);
     217        mpfr_clear (xr);
     218      }
     219    MPFR_SAVE_EXPO_FREE (expo);
     220    return underflow ? inexact : mpfr_check_range (y, inexact, rnd_mode);
     221  }
     222  
     223  int
     224  mpfr_tanpi (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
     225  {
     226    return mpfr_tanu (y, x, 2, rnd_mode);
     227  }