(root)/
mpfr-4.2.1/
src/
atan2.c
       1  /* mpfr_atan2 -- arc-tan 2 of a floating-point number
       2  
       3  Copyright 2005-2023 Free Software Foundation, Inc.
       4  Contributed by the AriC and Caramba 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 3 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.LESSER.  If not, see
      20  https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
      21  51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
      22  
      23  #define MPFR_NEED_LONGLONG_H
      24  #include "mpfr-impl.h"
      25  
      26  static int
      27  pi_div_2ui (mpfr_ptr dest, int i, int neg, mpfr_rnd_t rnd_mode)
      28  {
      29    int inexact;
      30    MPFR_SAVE_EXPO_DECL (expo);
      31  
      32    MPFR_SAVE_EXPO_MARK (expo);
      33    if (neg) /* -PI/2^i */
      34      {
      35        inexact = - mpfr_const_pi (dest, MPFR_INVERT_RND (rnd_mode));
      36        MPFR_CHANGE_SIGN (dest);
      37      }
      38    else /* PI/2^i */
      39      {
      40        inexact = mpfr_const_pi (dest, rnd_mode);
      41      }
      42    mpfr_div_2ui (dest, dest, i, rnd_mode);  /* exact */
      43    MPFR_SAVE_EXPO_FREE (expo);
      44    return mpfr_check_range (dest, inexact, rnd_mode);
      45  }
      46  
      47  int
      48  mpfr_atan2 (mpfr_ptr dest, mpfr_srcptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
      49  {
      50    mpfr_t tmp, pi;
      51    int inexact;
      52    mpfr_prec_t prec;
      53    mpfr_exp_t e;
      54    MPFR_SAVE_EXPO_DECL (expo);
      55    MPFR_ZIV_DECL (loop);
      56  
      57    MPFR_LOG_FUNC
      58      (("y[%Pd]=%.*Rg x[%Pd]=%.*Rg rnd=%d",
      59        mpfr_get_prec (y), mpfr_log_prec, y,
      60        mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode),
      61       ("atan[%Pd]=%.*Rg inexact=%d",
      62        mpfr_get_prec (dest), mpfr_log_prec, dest, inexact));
      63  
      64    /* Special cases */
      65    if (MPFR_ARE_SINGULAR (x, y))
      66      {
      67        /* atan2(0, 0) does not raise the "invalid" floating-point
      68           exception, nor does atan2(y, 0) raise the "divide-by-zero"
      69           floating-point exception.
      70           -- atan2(±0, -0) returns ±pi.313)
      71           -- atan2(±0, +0) returns ±0.
      72           -- atan2(±0, x) returns ±pi, for x < 0.
      73           -- atan2(±0, x) returns ±0, for x > 0.
      74           -- atan2(y, ±0) returns -pi/2 for y < 0.
      75           -- atan2(y, ±0) returns pi/2 for y > 0.
      76           -- atan2(±oo, -oo) returns ±3pi/4.
      77           -- atan2(±oo, +oo) returns ±pi/4.
      78           -- atan2(±oo, x) returns ±pi/2, for finite x.
      79           -- atan2(±y, -oo) returns ±pi, for finite y > 0.
      80           -- atan2(±y, +oo) returns ±0, for finite y > 0.
      81        */
      82        if (MPFR_IS_NAN (x) || MPFR_IS_NAN (y))
      83          {
      84            MPFR_SET_NAN (dest);
      85            MPFR_RET_NAN;
      86          }
      87        if (MPFR_IS_ZERO (y))
      88          {
      89            if (MPFR_IS_NEG (x)) /* +/- PI */
      90              {
      91              set_pi:
      92                if (MPFR_IS_NEG (y))
      93                  {
      94                    inexact =  mpfr_const_pi (dest, MPFR_INVERT_RND (rnd_mode));
      95                    MPFR_CHANGE_SIGN (dest);
      96                    return -inexact;
      97                  }
      98                else
      99                  return mpfr_const_pi (dest, rnd_mode);
     100              }
     101            else /* +/- 0 */
     102              {
     103              set_zero:
     104                MPFR_SET_ZERO (dest);
     105                MPFR_SET_SAME_SIGN (dest, y);
     106                return 0;
     107              }
     108          }
     109        if (MPFR_IS_ZERO (x))
     110          {
     111            return pi_div_2ui (dest, 1, MPFR_IS_NEG (y), rnd_mode);
     112          }
     113        if (MPFR_IS_INF (y))
     114          {
     115            if (!MPFR_IS_INF (x)) /* +/- PI/2 */
     116              return pi_div_2ui (dest, 1, MPFR_IS_NEG (y), rnd_mode);
     117            else if (MPFR_IS_POS (x)) /* +/- PI/4 */
     118              return pi_div_2ui (dest, 2, MPFR_IS_NEG (y), rnd_mode);
     119            else /* +/- 3*PI/4: Ugly since we have to round properly */
     120              {
     121                mpfr_t tmp2;
     122                MPFR_ZIV_DECL (loop2);
     123                mpfr_prec_t prec2 = MPFR_PREC (dest) + 10;
     124  
     125                MPFR_SAVE_EXPO_MARK (expo);
     126                mpfr_init2 (tmp2, prec2);
     127                MPFR_ZIV_INIT (loop2, prec2);
     128                for (;;)
     129                  {
     130                    mpfr_const_pi (tmp2, MPFR_RNDN);
     131                    mpfr_mul_ui (tmp2, tmp2, 3, MPFR_RNDN); /* Error <= 2  */
     132                    mpfr_div_2ui (tmp2, tmp2, 2, MPFR_RNDN);
     133                    if (MPFR_CAN_ROUND (tmp2, MPFR_PREC (tmp2) - 2,
     134                                        MPFR_PREC (dest), rnd_mode))
     135                      break;
     136                    MPFR_ZIV_NEXT (loop2, prec2);
     137                    mpfr_set_prec (tmp2, prec2);
     138                  }
     139                MPFR_ZIV_FREE (loop2);
     140                if (MPFR_IS_NEG (y))
     141                  MPFR_CHANGE_SIGN (tmp2);
     142                inexact = mpfr_set (dest, tmp2, rnd_mode);
     143                mpfr_clear (tmp2);
     144                MPFR_SAVE_EXPO_FREE (expo);
     145                return mpfr_check_range (dest, inexact, rnd_mode);
     146              }
     147          }
     148        MPFR_ASSERTD (MPFR_IS_INF (x));
     149        if (MPFR_IS_NEG (x))
     150          goto set_pi;
     151        else
     152          goto set_zero;
     153      }
     154  
     155    /* When x is a power of two, we call directly atan(y/x) since y/x is
     156       exact. */
     157    if (MPFR_UNLIKELY (MPFR_IS_POS (x) && mpfr_powerof2_raw (x)))
     158      {
     159        int r;
     160        mpfr_t yoverx;
     161        mpfr_flags_t saved_flags = __gmpfr_flags;
     162  
     163        mpfr_init2 (yoverx, MPFR_PREC (y));
     164        if (MPFR_LIKELY (mpfr_div_2si (yoverx, y, MPFR_GET_EXP (x) - 1,
     165                                       MPFR_RNDN) == 0))
     166          {
     167            /* Here the flags have not changed due to mpfr_div_2si. */
     168            r = mpfr_atan (dest, yoverx, rnd_mode);
     169            mpfr_clear (yoverx);
     170            return r;
     171          }
     172        else
     173          {
     174            /* Division is inexact because of a small exponent range */
     175            mpfr_clear (yoverx);
     176            __gmpfr_flags = saved_flags;
     177          }
     178      }
     179  
     180    MPFR_SAVE_EXPO_MARK (expo);
     181  
     182    /* Set up initial prec */
     183    prec = MPFR_PREC (dest) + 3 + MPFR_INT_CEIL_LOG2 (MPFR_PREC (dest));
     184    mpfr_init2 (tmp, prec);
     185  
     186    MPFR_ZIV_INIT (loop, prec);
     187    if (MPFR_IS_POS (x))
     188      /* use atan2(y,x) = atan(y/x) */
     189      for (;;)
     190        {
     191          int div_inex;
     192          MPFR_BLOCK_DECL (flags);
     193  
     194          MPFR_BLOCK (flags, div_inex = mpfr_div (tmp, y, x, MPFR_RNDN));
     195          if (div_inex == 0)
     196            {
     197              /* Result is exact. */
     198              inexact = mpfr_atan (dest, tmp, rnd_mode);
     199              goto end;
     200            }
     201  
     202          /* Error <= ulp (tmp) except in case of underflow or overflow. */
     203  
     204          /* If the division underflowed, since |atan(z)/z| < 1, we have
     205             an underflow. */
     206          if (MPFR_UNDERFLOW (flags))
     207            {
     208              int sign;
     209  
     210              /* In the case MPFR_RNDN with 2^(emin-2) < |y/x| < 2^(emin-1):
     211                 The smallest significand value S > 1 of |y/x| is:
     212                   * 1 / (1 - 2^(-px))                        if py <= px,
     213                   * (1 - 2^(-px) + 2^(-py)) / (1 - 2^(-px))  if py >= px.
     214                 Therefore S - 1 > 2^(-pz), where pz = max(px,py). We have:
     215                 atan(|y/x|) > atan(z), where z = 2^(emin-2) * (1 + 2^(-pz)).
     216                             > z - z^3 / 3.
     217                             > 2^(emin-2) * (1 + 2^(-pz) - 2^(2 emin - 5))
     218                 Assuming pz <= -2 emin + 5, we can round away from zero
     219                 (this is what mpfr_underflow always does on MPFR_RNDN).
     220                 In the case MPFR_RNDN with |y/x| <= 2^(emin-2), we round
     221                 toward zero, as |atan(z)/z| < 1. */
     222              MPFR_ASSERTN (MPFR_PREC_MAX <=
     223                            2 * (mpfr_uexp_t) - MPFR_EMIN_MIN + 5);
     224              if (rnd_mode == MPFR_RNDN && MPFR_IS_ZERO (tmp))
     225                rnd_mode = MPFR_RNDZ;
     226              sign = MPFR_SIGN (tmp);
     227              mpfr_clear (tmp);
     228              MPFR_SAVE_EXPO_FREE (expo);
     229              return mpfr_underflow (dest, rnd_mode, sign);
     230            }
     231  
     232          mpfr_atan (tmp, tmp, MPFR_RNDN);   /* Error <= 2*ulp (tmp) since
     233                                               abs(D(arctan)) <= 1 */
     234          /* TODO: check that the error bound is correct in case of overflow. */
     235          /* FIXME: Error <= ulp(tmp) ? */
     236          if (MPFR_LIKELY (MPFR_CAN_ROUND (tmp, prec - 2, MPFR_PREC (dest),
     237                                           rnd_mode)))
     238            break;
     239          MPFR_ZIV_NEXT (loop, prec);
     240          mpfr_set_prec (tmp, prec);
     241        }
     242    else /* x < 0 */
     243      /*  Use sign(y)*(PI - atan (|y/x|)) */
     244      {
     245        mpfr_init2 (pi, prec);
     246        for (;;)
     247          {
     248            mpfr_div (tmp, y, x, MPFR_RNDN);   /* Error <= ulp (tmp) */
     249            /* If tmp is 0, we have |y/x| <= 2^(-emin-2), thus
     250               atan|y/x| < 2^(-emin-2). */
     251            MPFR_SET_POS (tmp);               /* no error */
     252            mpfr_atan (tmp, tmp, MPFR_RNDN);   /* Error <= 2*ulp (tmp) since
     253                                                 abs(D(arctan)) <= 1 */
     254            mpfr_const_pi (pi, MPFR_RNDN);     /* Error <= ulp(pi) /2 */
     255            e = MPFR_NOTZERO(tmp) ? MPFR_GET_EXP (tmp) : __gmpfr_emin - 1;
     256            mpfr_sub (tmp, pi, tmp, MPFR_RNDN);          /* see above */
     257            if (MPFR_IS_NEG (y))
     258              MPFR_CHANGE_SIGN (tmp);
     259            /* Error(tmp) <= (1/2+2^(EXP(pi)-EXP(tmp)-1)+2^(e-EXP(tmp)+1))*ulp
     260                          <= 2^(MAX (MAX (EXP(PI)-EXP(tmp)-1, e-EXP(tmp)+1),
     261                                          -1)+2)*ulp(tmp) */
     262            e = MAX (MAX (MPFR_GET_EXP (pi)-MPFR_GET_EXP (tmp) - 1,
     263                          e - MPFR_GET_EXP (tmp) + 1), -1) + 2;
     264            if (MPFR_LIKELY (MPFR_CAN_ROUND (tmp, prec - e, MPFR_PREC (dest),
     265                                             rnd_mode)))
     266              break;
     267            MPFR_ZIV_NEXT (loop, prec);
     268            mpfr_set_prec (tmp, prec);
     269            mpfr_set_prec (pi, prec);
     270          }
     271        mpfr_clear (pi);
     272      }
     273    inexact = mpfr_set (dest, tmp, rnd_mode);
     274  
     275   end:
     276    MPFR_ZIV_FREE (loop);
     277    mpfr_clear (tmp);
     278    MPFR_SAVE_EXPO_FREE (expo);
     279    return mpfr_check_range (dest, inexact, rnd_mode);
     280  }