1 /* mpc_atan -- arctangent of a complex number.
3 Copyright (C) 2009 Philippe Th\'eveny, Paul Zimmermann
5 This file is part of the MPC Library.
7 The MPC Library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or (at your
10 option) any later version.
12 The MPC Library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with the MPC Library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 MA 02111-1307, USA. */
27 rounded in the direction rnd
30 set_pi_over_2 (mpfr_ptr rop, int s, mpfr_rnd_t rnd)
34 inex = mpfr_const_pi (rop, s < 0 ? INV_RND (rnd) : rnd);
35 mpfr_div_2ui (rop, rop, 1, GMP_RNDN);
39 mpfr_neg (rop, rop, GMP_RNDN);
46 mpc_atan (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
56 s_re = mpfr_signbit (MPC_RE (op));
57 s_im = mpfr_signbit (MPC_IM (op));
60 if (mpfr_nan_p (MPC_RE (op)) || mpfr_nan_p (MPC_IM (op)))
62 if (mpfr_nan_p (MPC_RE (op)))
64 mpfr_set_nan (MPC_RE (rop));
65 if (mpfr_zero_p (MPC_IM (op)) || mpfr_inf_p (MPC_IM (op)))
67 mpfr_set_ui (MPC_IM (rop), 0, GMP_RNDN);
69 mpc_conj (rop, rop, MPC_RNDNN);
72 mpfr_set_nan (MPC_IM (rop));
76 if (mpfr_inf_p (MPC_RE (op)))
78 inex_re = set_pi_over_2 (MPC_RE (rop), -s_re, MPC_RND_RE (rnd));
79 mpfr_set_ui (MPC_IM (rop), 0, GMP_RNDN);
83 mpfr_set_nan (MPC_RE (rop));
84 mpfr_set_nan (MPC_IM (rop));
87 return MPC_INEX (inex_re, 0);
90 if (mpfr_inf_p (MPC_RE (op)) || mpfr_inf_p (MPC_IM (op)))
92 inex_re = set_pi_over_2 (MPC_RE (rop), -s_re, MPC_RND_RE (rnd));
94 mpfr_set_ui (MPC_IM (rop), 0, GMP_RNDN);
96 mpc_conj (rop, rop, GMP_RNDN);
98 return MPC_INEX (inex_re, 0);
101 /* pure real argument */
102 if (mpfr_zero_p (MPC_IM (op)))
104 inex_re = mpfr_atan (MPC_RE (rop), MPC_RE (op), MPC_RND_RE (rnd));
106 mpfr_set_ui (MPC_IM (rop), 0, GMP_RNDN);
108 mpc_conj (rop, rop, GMP_RNDN);
110 return MPC_INEX (inex_re, 0);
113 /* pure imaginary argument */
114 if (mpfr_zero_p (MPC_RE (op)))
119 cmp_1 = -mpfr_cmp_si (MPC_IM (op), -1);
121 cmp_1 = mpfr_cmp_ui (MPC_IM (op), +1);
125 /* atan(+0+iy) = +0 +i*atanh(y), if |y| < 1
126 atan(-0+iy) = -0 +i*atanh(y), if |y| < 1 */
128 mpfr_set_ui (MPC_RE (rop), 0, GMP_RNDN);
130 mpfr_neg (MPC_RE (rop), MPC_RE (rop), GMP_RNDN);
132 inex_im = mpfr_atanh (MPC_IM (rop), MPC_IM (op), MPC_RND_IM (rnd));
136 /* atan(+/-0+i) = NaN +i*inf
137 atan(+/-0-i) = NaN -i*inf */
138 mpfr_set_nan (MPC_RE (rop));
139 mpfr_set_inf (MPC_IM (rop), s_im ? -1 : +1);
143 /* atan(+0+iy) = +pi/2 +i*atanh(1/y), if |y| > 1
144 atan(-0+iy) = -pi/2 +i*atanh(1/y), if |y| > 1 */
145 mp_rnd_t rnd_im, rnd_away;
150 rnd_im = MPC_RND_IM (rnd);
152 p_im = mpfr_get_prec (MPC_IM (rop));
155 /* a = o(1/y) with error(a) < 1 ulp(a)
156 b = o(atanh(a)) with error(b) < (1+2^{1+Exp(a)-Exp(b)}) ulp(b)
158 As |atanh (1/y)| > |1/y| we have Exp(a)-Exp(b) <=0 so, at most,
159 2 bits of precision are lost.
161 We round atanh(1/y) away from 0.
165 p += mpc_ceil_log2 (p) + 2;
166 mpfr_set_prec (y, p);
167 rnd_away = s_im == 0 ? GMP_RNDU : GMP_RNDD;
168 inex_im = mpfr_ui_div (y, 1, MPC_IM (op), rnd_away);
169 /* FIXME: should we consider the case with unreasonably huge
170 precision prec(y)>3*exp_min, where atanh(1/Im(op)) could be
171 representable while 1/Im(op) underflows ?
172 This corresponds to |y| = 0.5*2^emin, in which case the
173 result may be wrong. */
175 /* atanh cannot underflow: |atanh(x)| > |x| for |x| < 1 */
176 inex_im |= mpfr_atanh (y, y, rnd_away);
179 || mpfr_can_round (y, p - 2, rnd_away, GMP_RNDZ,
180 p_im + (rnd_im == GMP_RNDN));
183 inex_re = set_pi_over_2 (MPC_RE (rop), -s_re, MPC_RND_RE (rnd));
184 inex_im = mpfr_set (MPC_IM (rop), y, rnd_im);
187 return MPC_INEX (inex_re, inex_im);
190 /* regular number argument */
201 mpfr_inits (a, b, x, y, (mpfr_ptr) 0);
203 /* real part: Re(arctan(x+i*y)) = [arctan2(x,1-y) - arctan2(-x,1+y)]/2 */
204 minus_op_re[0] = MPC_RE (op)[0];
205 MPFR_CHANGE_SIGN (minus_op_re);
206 op_re_exp = MPFR_EXP (MPC_RE (op));
207 op_im_exp = MPFR_EXP (MPC_IM (op));
209 prec = mpfr_get_prec (MPC_RE (rop)); /* result precision */
211 /* a = o(1-y) error(a) < 1 ulp(a)
212 b = o(atan2(x,a)) error(b) < [1+2^{3+Exp(x)-Exp(a)-Exp(b)}] ulp(b)
214 c = o(1+y) error(c) < 1 ulp(c)
215 d = o(atan2(-x,c)) error(d) < [1+2^{3+Exp(x)-Exp(c)-Exp(d)}] ulp(d)
217 e = o(b - d) error(e) < [1 + kb*2^{Exp(b}-Exp(e)}
218 + kd*2^{Exp(d)-Exp(e)}] ulp(e)
219 error(e) < [1 + 2^{4+Exp(x)-Exp(a)-Exp(e)}
220 + 2^{4+Exp(x)-Exp(c)-Exp(e)}] ulp(e)
221 because |atan(u)| < |u|
222 < [1 + 2^{5+Exp(x)-min(Exp(a),Exp(c))
227 /* p: working precision */
228 p = (op_im_exp > 0 || prec > SAFE_ABS (mp_prec_t, op_im_exp)) ? prec
229 : (prec - op_im_exp);
230 rnd1 = mpfr_sgn (MPC_RE (op)) > 0 ? GMP_RNDD : GMP_RNDU;
231 rnd2 = mpfr_sgn (MPC_RE (op)) < 0 ? GMP_RNDU : GMP_RNDD;
235 p += mpc_ceil_log2 (p) + 2;
236 mpfr_set_prec (a, p);
237 mpfr_set_prec (b, p);
238 mpfr_set_prec (x, p);
240 /* x = upper bound for atan (x/(1-y)). Since atan is increasing, we
241 need an upper bound on x/(1-y), i.e., a lower bound on 1-y for
242 x positive, and an upper bound on 1-y for x negative */
243 mpfr_ui_sub (a, 1, MPC_IM (op), rnd1);
244 if (mpfr_sgn (a) == 0) /* y is near 1, thus 1+y is near 2, and
245 expo will be 1 or 2 below */
247 if (mpfr_cmp_ui (MPC_IM(op), 1) != 0)
249 err = 2; /* ensures err will be expo below */
252 err = MPFR_EXP (a); /* err = Exp(a) with the notations above */
253 mpfr_atan2 (x, MPC_RE (op), a, GMP_RNDU);
255 /* b = lower bound for atan (-x/(1+y)): for x negative, we need a
256 lower bound on -x/(1+y), i.e., an upper bound on 1+y */
257 mpfr_add_ui (a, MPC_IM(op), 1, rnd2);
258 /* if a is zero but inexact, try again with a larger precision
259 if a is exactly zero, i.e., Im(op) = -1, then the error on a is 0,
260 and we can simply ignore the terms involving Exp(a) in the error */
261 if (mpfr_sgn (a) == 0)
263 if (mpfr_cmp_si (MPC_IM(op), -1) != 0)
265 expo = err; /* will leave err unchanged below */
268 expo = MPFR_EXP (a); /* expo = Exp(c) with the notations above */
269 mpfr_atan2 (b, minus_op_re, a, GMP_RNDD);
271 err = err < expo ? err : expo; /* err = min(Exp(a),Exp(c)) */
272 mpfr_sub (x, x, b, GMP_RNDU);
274 err = 5 + op_re_exp - err - MPFR_EXP (x);
275 /* error is bounded by [1 + 2^err] ulp(e) */
276 err = err < 0 ? 1 : err + 1;
278 mpfr_div_2ui (x, x, 1, GMP_RNDU);
280 /* Note: using RND2=RNDD guarantees that if x is exactly representable
281 on prec + ... bits, mpfr_can_round will return 0 */
282 ok = mpfr_can_round (x, p - err, GMP_RNDU, GMP_RNDD,
283 prec + (MPC_RND_RE (rnd) == GMP_RNDN));
287 Im(atan(x+I*y)) = 1/4 * [log(x^2+(1+y)^2) - log (x^2 +(1-y)^2)] */
288 prec = mpfr_get_prec (MPC_IM (rop)); /* result precision */
290 /* a = o(1+y) error(a) < 1 ulp(a)
291 b = o(a^2) error(b) < 5 ulp(b)
292 c = o(x^2) error(c) < 1 ulp(c)
293 d = o(b+c) error(d) < 7 ulp(d)
294 e = o(log(d)) error(e) < [1 + 7*2^{2-Exp(e)}] ulp(e) = ke ulp(e)
295 f = o(1-y) error(f) < 1 ulp(f)
296 g = o(f^2) error(g) < 5 ulp(g)
297 h = o(c+f) error(h) < 7 ulp(h)
298 i = o(log(h)) error(i) < [1 + 7*2^{2-Exp(i)}] ulp(i) = ki ulp(i)
299 j = o(e-i) error(j) < [1 + ke*2^{Exp(e)-Exp(j)}
300 + ki*2^{Exp(i)-Exp(j)}] ulp(j)
301 error(j) < [1 + 2^{Exp(e)-Exp(j)} + 2^{Exp(i)-Exp(j)}
302 + 7*2^{3-Exp(j)}] ulp(j)
303 < [1 + 2^{max(Exp(e),Exp(i))-Exp(j)+1}
304 + 7*2^{3-Exp(j)}] ulp(j)
308 p = prec; /* working precision */
309 rnd1 = mpfr_cmp_si (MPC_IM (op), -1) > 0 ? GMP_RNDU : GMP_RNDD;
313 p += mpc_ceil_log2 (p) + err;
314 mpfr_set_prec (a, p);
315 mpfr_set_prec (b, p);
316 mpfr_set_prec (y, p);
318 /* a = upper bound for log(x^2 + (1+y)^2) */
319 mpfr_add_ui (a, MPC_IM (op), 1, rnd1);
320 mpfr_sqr (a, a, GMP_RNDU);
321 mpfr_sqr (y, MPC_RE (op), GMP_RNDU);
322 mpfr_add (a, a, y, GMP_RNDU);
323 mpfr_log (a, a, GMP_RNDU);
325 /* b = lower bound for log(x^2 + (1-y)^2) */
326 mpfr_ui_sub (b, 1, MPC_IM (op), GMP_RNDZ);
327 mpfr_sqr (b, b, GMP_RNDU);
328 /* mpfr_sqr (y, MPC_RE (op), GMP_RNDZ); */
330 mpfr_add (b, b, y, GMP_RNDZ);
331 mpfr_log (b, b, GMP_RNDZ);
333 mpfr_sub (y, a, b, GMP_RNDU);
335 expo = MPFR_EXP (a) < MPFR_EXP (b) ? MPFR_EXP (b) : MPFR_EXP (a);
336 expo = expo - MPFR_EXP (y) + 1;
337 err = 3 - MPFR_EXP (y);
338 /* error(j) <= [1 + 2^expo + 7*2^err] ulp(j) */
339 if (expo <= err) /* error(j) <= [1 + 2^{err+1}] ulp(j) */
340 err = (err < 0) ? 1 : err + 2;
342 err = (expo < 0) ? 1 : expo + 2;
344 mpfr_div_2ui (y, y, 2, GMP_RNDN);
346 err = 2; /* underflow */
348 ok = mpfr_can_round (y, p - err, GMP_RNDU, GMP_RNDD,
349 prec + (MPC_RND_IM (rnd) == GMP_RNDN));
352 inex = mpc_set_fr_fr (rop, x, y, rnd);
354 mpfr_clears (a, b, x, y, (mpfr_ptr) 0);