1/* mpfr_atan2 -- arc-tan 2 of a floating-point number
2
3Copyright 2005-2023 Free Software Foundation, Inc.
4Contributed by the AriC and Caramba projects, INRIA.
5
6This file is part of the GNU MPFR Library.
7
8The GNU MPFR Library is free software; you can redistribute it and/or modify
9it under the terms of the GNU Lesser General Public License as published by
10the Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13The GNU MPFR Library is distributed in the hope that it will be useful, but
14WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16License for more details.
17
18You should have received a copy of the GNU Lesser General Public License
19along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
20https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
2151 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22
23#define MPFR_NEED_LONGLONG_H
24#include "mpfr-impl.h"
25
26static int
27pi_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
47int
48mpfr_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[%Pu]=%.*Rg x[%Pu]=%.*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[%Pu]=%.*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}
281