xref: /netbsd-src/external/lgpl3/mpfr/dist/src/atan2.c (revision ec6772edaf0cdcb5f52a48f4aca5e33a8fb8ecfd)
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
pi_div_2ui(mpfr_ptr dest,int i,int neg,mpfr_rnd_t rnd_mode)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
mpfr_atan2(mpfr_ptr dest,mpfr_srcptr y,mpfr_srcptr x,mpfr_rnd_t rnd_mode)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 }
281