1 /* mpfr_atan2u -- atan2u(y,x,u) = atan(|y/x|)*u/(2*pi) for x > 0
2 atan2u(y,x,u) = 1-atan(|y/x|)*u/(2*pi) for x < 0
3 mpfr_atan2pi -- atan2pi(x) = atan2u(u=2)
4
5 Copyright 2021-2023 Free Software Foundation, Inc.
6 Contributed by the AriC and Caramba projects, INRIA.
7
8 This file is part of the GNU MPFR Library.
9
10 The GNU MPFR Library is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or (at your
13 option) any later version.
14
15 The GNU MPFR Library is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18 License for more details.
19
20 You should have received a copy of the GNU Lesser General Public License
21 along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
22 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
24
25 #define MPFR_NEED_LONGLONG_H
26 #include "mpfr-impl.h"
27
28 #define ULSIZE (sizeof (unsigned long) * CHAR_BIT)
29
30 /* z <- s*u*2^e, with e between -3 and -1 */
31 static int
mpfr_atan2u_aux1(mpfr_ptr z,unsigned long u,int e,int s,mpfr_rnd_t rnd_mode)32 mpfr_atan2u_aux1 (mpfr_ptr z, unsigned long u, int e, int s,
33 mpfr_rnd_t rnd_mode)
34 {
35 if (s > 0)
36 return mpfr_set_ui_2exp (z, u, e, rnd_mode);
37 else
38 {
39 int inex;
40
41 rnd_mode = MPFR_INVERT_RND (rnd_mode);
42 inex = mpfr_set_ui_2exp (z, u, e, rnd_mode);
43 MPFR_CHANGE_SIGN (z);
44 return -inex;
45 }
46 }
47
48 /* z <- s*3*u*2^e, with e between -3 and -1 */
49 static int
mpfr_atan2u_aux2(mpfr_ptr z,unsigned long u,int e,int s,mpfr_rnd_t rnd_mode)50 mpfr_atan2u_aux2 (mpfr_ptr z, unsigned long u, int e, int s,
51 mpfr_rnd_t rnd_mode)
52 {
53 int inex;
54 mpfr_t t;
55 MPFR_SAVE_EXPO_DECL (expo);
56
57 MPFR_SAVE_EXPO_MARK (expo);
58 mpfr_init2 (t, ULSIZE + 2);
59 inex = mpfr_set_ui_2exp (t, u, e, MPFR_RNDZ); /* exact */
60 MPFR_ASSERTD (inex == 0);
61 inex = mpfr_mul_ui (t, t, 3, MPFR_RNDZ); /* exact */
62 MPFR_ASSERTD (inex == 0);
63 if (s < 0)
64 MPFR_CHANGE_SIGN (t);
65 inex = mpfr_set (z, t, rnd_mode);
66 mpfr_clear (t);
67 MPFR_SAVE_EXPO_FREE (expo);
68 return mpfr_check_range (z, inex, rnd_mode);
69 }
70
71 /* return round(sign(s)*(u/2-eps),rnd_mode), where eps < 1/2*ulp(u/2) */
72 static int
mpfr_atan2u_aux3(mpfr_ptr z,unsigned long u,int s,mpfr_rnd_t rnd_mode)73 mpfr_atan2u_aux3 (mpfr_ptr z, unsigned long u, int s, mpfr_rnd_t rnd_mode)
74 {
75 mpfr_t t;
76 mpfr_prec_t prec;
77 int inex;
78
79 prec = (MPFR_PREC(z) + 2 > ULSIZE) ? MPFR_PREC(z) + 2 : ULSIZE;
80 /* prec >= PREC(z)+2 and prec >= ULSIZE */
81 mpfr_init2 (t, prec);
82 mpfr_set_ui_2exp (t, u, -1, MPFR_RNDN); /* exact since prec >= ULSIZE */
83 mpfr_nextbelow (t);
84 /* u/2 - 1/4*ulp_p(u/2) <= t <= u/2, where p = PREC(z),
85 which ensures round_p(t) = round_p(u/2-eps) */
86 if (s < 0)
87 mpfr_neg (t, t, MPFR_RNDN);
88 inex = mpfr_set (z, t, rnd_mode);
89 mpfr_clear (t);
90 return inex;
91 }
92
93 /* return round(sign(y)*(u/4-sign(x)*eps),rnd_mode),
94 where eps < 1/2*ulp(u/4) */
95 static int
mpfr_atan2u_aux4(mpfr_ptr z,mpfr_srcptr y,mpfr_srcptr x,unsigned long u,mpfr_rnd_t rnd_mode)96 mpfr_atan2u_aux4 (mpfr_ptr z, mpfr_srcptr y, mpfr_srcptr x, unsigned long u,
97 mpfr_rnd_t rnd_mode)
98 {
99 mpfr_t t;
100 mpfr_prec_t prec;
101 int inex;
102
103 prec = (MPFR_PREC(z) > ULSIZE) ? MPFR_PREC(z) + 2 : ULSIZE + 2;
104 /* prec >= PREC(z)+2 and prec >= ULSIZE + 2 */
105 mpfr_init2 (t, prec);
106 mpfr_set_ui_2exp (t, u, -2, MPFR_RNDN); /* exact */
107 if (MPFR_SIGN(x) > 0)
108 mpfr_nextbelow (t);
109 else
110 mpfr_nextabove (t);
111 if (MPFR_SIGN(y) < 0)
112 mpfr_neg (t, t, MPFR_RNDN);
113 inex = mpfr_set (z, t, rnd_mode);
114 mpfr_clear (t);
115 return inex;
116 }
117
118 /* deal with underflow case, i.e., when y/x rounds to zero */
119 static int
mpfr_atan2u_underflow(mpfr_ptr z,mpfr_srcptr y,mpfr_srcptr x,unsigned long u,mpfr_rnd_t rnd_mode)120 mpfr_atan2u_underflow (mpfr_ptr z, mpfr_srcptr y, mpfr_srcptr x,
121 unsigned long u, mpfr_rnd_t rnd_mode)
122 {
123 mpfr_exp_t e = MPFR_GET_EXP(y) - MPFR_GET_EXP(x) + (ULSIZE - 1);
124 /* Detect underflow: since |atan(|y/x|)| < |y/x| for |y/x| < 1,
125 |atan2u(y,x,u)| < |y/x|*u/(2*pi) < 2^(ULSIZE-2)*|y/x|
126 < 2^(EXP(y)-EXP(x)+(ULSIZE-1)).
127 For x > 0, we have underflow when
128 EXP(y)-EXP(x)+(ULSIZE-1) < emin.
129 For x < 0, we have underflow when
130 EXP(y)-EXP(x)+(ULSIZE-1) < EXP(u/2)-prec. */
131 if (MPFR_IS_POS(x))
132 {
133 MPFR_ASSERTN(e < __gmpfr_emin);
134 return mpfr_underflow (z,
135 (rnd_mode == MPFR_RNDN) ? MPFR_RNDZ : rnd_mode, MPFR_SIGN(y));
136 }
137 else
138 {
139 MPFR_ASSERTD (MPFR_IS_NEG(x));
140 MPFR_ASSERTN(e < (ULSIZE - 1) - MPFR_PREC(z));
141 return mpfr_atan2u_aux3 (z, u, MPFR_SIGN(y), rnd_mode);
142 }
143 }
144
145 /* deal with overflow case, i.e., when y/x rounds to infinity */
146 static int
mpfr_atan2u_overflow(mpfr_ptr z,mpfr_srcptr y,mpfr_srcptr x,unsigned long u,mpfr_rnd_t rnd_mode)147 mpfr_atan2u_overflow (mpfr_ptr z, mpfr_srcptr y, mpfr_srcptr x,
148 unsigned long u, mpfr_rnd_t rnd_mode)
149 {
150 /* When t goes to +Inf, pi/2 - 1/t < atan(t) < pi/2,
151 thus u/4 - u/(2*pi*t) < atanu(t) < u/4.
152 As soon as u/(2*pi*t) < 1/2*ulp(u/4), the result is either u/4
153 or the number just below.
154 Here t = y/x, thus 1/t <= x/y < 2^(EXP(x)-EXP(y)+1),
155 and u/(2*pi*t) < 2^(EXP(x)-EXP(y)+(ULSIZE-2)). */
156 mpfr_exp_t e = MPFR_GET_EXP(x) - MPFR_GET_EXP(y) + (ULSIZE - 2);
157 mpfr_exp_t ulpz = (ULSIZE - 2) - MPFR_PREC(z); /* ulp(u/4) <= 2^ulpz */
158 MPFR_ASSERTN (e < ulpz - 1);
159 return mpfr_atan2u_aux4 (z, y, x, u, rnd_mode);
160 }
161
162 /* put in z the correctly rounded value of atan2y(y,x,u) */
163 int
mpfr_atan2u(mpfr_ptr z,mpfr_srcptr y,mpfr_srcptr x,unsigned long u,mpfr_rnd_t rnd_mode)164 mpfr_atan2u (mpfr_ptr z, mpfr_srcptr y, mpfr_srcptr x, unsigned long u,
165 mpfr_rnd_t rnd_mode)
166 {
167 mpfr_t tmp;
168 mpfr_prec_t prec;
169 int inex;
170 MPFR_SAVE_EXPO_DECL (expo);
171 MPFR_ZIV_DECL (loop);
172
173 MPFR_LOG_FUNC
174 (("y[%Pd]=%.*Rg x[%Pd]=%.*Rg u=%lu rnd=%d",
175 mpfr_get_prec(y), mpfr_log_prec, y,
176 mpfr_get_prec(x), mpfr_log_prec, x,
177 u, rnd_mode),
178 ("z[%Pd]=%.*Rg inexact=%d", mpfr_get_prec (z), mpfr_log_prec, z,
179 inex));
180
181 /* Special cases */
182 if (MPFR_ARE_SINGULAR (x, y))
183 {
184 if (MPFR_IS_NAN (x) || MPFR_IS_NAN (y))
185 {
186 MPFR_SET_NAN (z);
187 MPFR_RET_NAN;
188 }
189 /* remains (y=Inf,x=Inf), (Inf,0), (Inf,regular), (0,Inf), (0,0),
190 (0,regular), (regular,Inf), (regular,0) */
191 if (MPFR_IS_INF (x))
192 {
193 /* cases (y=Inf,x=Inf), (0,Inf), (regular,Inf) */
194 if (MPFR_IS_INF (y))
195 {
196 if (MPFR_IS_NEG (x))
197 {
198 /* atan2Pi(+/-Inf,-Inf) = +/-3/4,
199 atan2u(+/-Inf,-Inf,u) = +/-3u/8 */
200 return mpfr_atan2u_aux2 (z, u, -3, MPFR_SIGN (y), rnd_mode);
201 }
202 else /* x > 0 */
203 {
204 /* atan2Pi(+/-Inf,-Inf) = +/-1/4,
205 atan2u(+/-Inf,-Inf,u) = +/-u/8 */
206 return mpfr_atan2u_aux1 (z, u, -3, MPFR_SIGN (y), rnd_mode);
207 }
208 }
209 /* remains (y,x) = (0,Inf) and (regular,Inf),
210 in which cases the IEEE 754-2019 rules for (y=0,x<>0)
211 and for (y<>0,x Inf) coincide */
212 if (MPFR_IS_NEG (x))
213 /* y>0: atan2Pi(+/-y,-Inf) = +/-1,
214 atan2u(+/-y,-Inf,u) = +/-u/2 */
215 return mpfr_atan2u_aux1 (z, u, -1, MPFR_SIGN (y), rnd_mode);
216 else
217 {
218 /* y>0: atan2Pi(+/-y,+Inf) = +/-0,
219 atan2u(+/-y,+Inf,u) = +/-0 */
220 MPFR_SET_ZERO (z);
221 MPFR_SET_SAME_SIGN (z, y);
222 MPFR_RET (0);
223 }
224 }
225 /* remains (y=Inf,x=0), (Inf,regular), (0,0), (0,regular), (regular,0) */
226 if (MPFR_IS_INF (y))
227 /* x is zero or regular */
228 /* atan2Pi(+/-Inf, x) = +/-1/2, atan2u(+/-Inf, x, u) = +/-u/4 */
229 return mpfr_atan2u_aux1 (z, u, -2, MPFR_SIGN(y), rnd_mode);
230 /* remains (y=0,x=0), (0,regular), (regular,0) */
231 if (MPFR_IS_ZERO (y))
232 {
233 if (MPFR_IS_NEG (x))
234 {
235 /* atan2Pi(+/-0, x) = +/-1, atan2u(+/-0, x, u) = +/-u/2 */
236 return mpfr_atan2u_aux1 (z, u, -1, MPFR_SIGN(y), rnd_mode);
237 }
238 else /* case x = +0 or x > 0 */
239 {
240 /* atan2Pi(+/-0, x) = +/-0, atan2u(+/-0, x, u) = +/-0 */
241 MPFR_SET_ZERO (z); /* does not modify sign, in case z=y */
242 MPFR_SET_SAME_SIGN (z, y);
243 MPFR_RET (0); /* exact result */
244 }
245 }
246 /* remains (regular,0) */
247 if (MPFR_IS_ZERO (x))
248 {
249 /* y<0: atan2Pi(y,+/-0) = -1/2, thus atan2u(y,+/-0,u) = -u/4 */
250 /* y>0: atan2Pi(y,+/-0) = 1/2, thus atan2u(y,+/-0,u) = u/4 */
251 return mpfr_atan2u_aux1 (z, u, -2, MPFR_SIGN(y), rnd_mode);
252 }
253 /* no special case should remain */
254 MPFR_RET_NEVER_GO_HERE ();
255 }
256
257 /* IEEE 754-2019 says that atan2Pi is odd with respect to y */
258
259 /* now both y and x are regular */
260 if (mpfr_cmpabs (y, x) == 0)
261 {
262 if (MPFR_IS_POS (x))
263 /* atan2u (+/-x,x,u) = +/u/8 for x > 0 */
264 return mpfr_atan2u_aux1 (z, u, -3, MPFR_SIGN(y), rnd_mode);
265 else /* x < 0 */
266 /* atan2u (+/-x,x,u) = -/+3u/8 for x > 0 */
267 return mpfr_atan2u_aux2 (z, u, -3, MPFR_SIGN(y), rnd_mode);
268 }
269
270 if (u == 0) /* return 0 with sign of y for x > 0,
271 and 1 with sign of y for x < 0 */
272 {
273 if (MPFR_SIGN(x) > 0)
274 {
275 MPFR_SET_ZERO (z);
276 MPFR_SET_SAME_SIGN (z, y);
277 MPFR_RET (0);
278 }
279 else
280 return mpfr_set_si (z, MPFR_SIGN(y) > 0 ? 1 : -1, rnd_mode);
281 }
282
283 MPFR_SAVE_EXPO_MARK (expo);
284 prec = MPFR_PREC (z);
285 prec += MPFR_INT_CEIL_LOG2(prec) + 10;
286 mpfr_init2 (tmp, prec);
287 MPFR_ZIV_INIT (loop, prec);
288 for (;;)
289 {
290 mpfr_exp_t expt, e;
291 /* atan2u(-y,x,u) = -atan(y,x,u)
292 atan2u(y,x,u) = atan(|y/x|)*u/(2*pi) for x > 0
293 atan2u(y,x,u) = u/2-atan(|y/x|)*u/(2*pi) for x < 0
294 atan2pi atan2u
295 First quadrant: [0,1/2] [0,u/4]
296 Second quadrant: [1/2,1] [u/4,u/2]
297 Third quadrant: [-1,-1/2] [-u/2,-u/4]
298 Fourth quadrant: [-1/2,0] [-u/4,0] */
299 inex = mpfr_div (tmp, y, x, MPFR_RNDN);
300 if (MPFR_IS_ZERO(tmp))
301 {
302 mpfr_clear (tmp);
303 MPFR_SAVE_EXPO_FREE (expo);
304 return mpfr_atan2u_underflow (z, y, x, u, rnd_mode);
305 }
306 if (MPFR_IS_INF(tmp))
307 {
308 mpfr_clear (tmp);
309 MPFR_SAVE_EXPO_FREE (expo);
310 return mpfr_atan2u_overflow (z, y, x, u, rnd_mode);
311 }
312 MPFR_SET_SIGN (tmp, 1);
313 expt = MPFR_GET_EXP(tmp);
314 /* |tmp - |y/x|| <= e1 := 1/2*ulp(tmp) = 2^(expt-prec-1) */
315 inex |= mpfr_atanu (tmp, tmp, u, MPFR_RNDN);
316 /* the derivative of atan(t) is 1/(1+t^2), thus that of atanu(t) is
317 u/(1+t^2)/(2*pi), and if tmp2 is the new value of tmp, we have
318 |tmp2 - atanu|y/x|| <= 1/2*ulp(tmp2) + e1*u/(1+tmp^2)/4 */
319 e = (expt < 1) ? 0 : expt - 1;
320 /* max(1,|tmp|) >= 2^e thus 1/(1+tmp^2) <= 2^(-2*e) */
321 e = expt - 2 * e + MPFR_INT_CEIL_LOG2(u) - 2;
322 /* now e1*u/(1+tmp^2)/4 <= 2^(e-prec-1) */
323 /* |tmp2 - atanu(y/x)| <= 1/2*ulp(tmp2) + 2^(e-prec-1) */
324 e = (e < MPFR_GET_EXP(tmp)) ? MPFR_GET_EXP(tmp) : e;
325 /* |tmp2 - atanu(y/x)| <= 2^(e-prec) */
326 if (MPFR_SIGN (x) < 0)
327 { /* compute u/2-tmp */
328 mpfr_mul_2ui (tmp, tmp, 1, MPFR_RNDN); /* error <= 2^(e+1-prec) */
329 mpfr_ui_sub (tmp, u, tmp, MPFR_RNDN);
330 expt = MPFR_GET_EXP(tmp);
331 /* error <= 2^(expt-prec-1) + 2^(e+1-prec) */
332 e = (expt - 1 > e + 1) ? expt - 1 : e + 1;
333 /* error <= 2^(e+1-prec) */
334 mpfr_div_2ui (tmp, tmp, 1, MPFR_RNDN);
335 /* error <= 2^(e-prec) */
336 }
337 /* both with x>0 and x<0, we have error <= 2^(e-prec),
338 now we want error <= 2^(expt-prec+err)
339 thus err = e-expt */
340 e -= MPFR_GET_EXP(tmp);
341 if (MPFR_SIGN(y) < 0) /* atan2u is odd with respect to y */
342 MPFR_CHANGE_SIGN(tmp);
343 if (MPFR_LIKELY (MPFR_CAN_ROUND (tmp, prec - e,
344 MPFR_PREC (z), rnd_mode)))
345 break;
346 MPFR_ZIV_NEXT (loop, prec);
347 mpfr_set_prec (tmp, prec);
348 }
349 MPFR_ZIV_FREE (loop);
350 inex = mpfr_set (z, tmp, rnd_mode);
351 mpfr_clear (tmp);
352 MPFR_SAVE_EXPO_FREE (expo);
353
354 return mpfr_check_range (z, inex, rnd_mode);
355 }
356
357 int
mpfr_atan2pi(mpfr_ptr z,mpfr_srcptr y,mpfr_srcptr x,mpfr_rnd_t rnd_mode)358 mpfr_atan2pi (mpfr_ptr z, mpfr_srcptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
359 {
360 return mpfr_atan2u (z, y, x, 2, rnd_mode);
361 }
362