1*d30dc8cbSJohn Marino /* mpc_div -- Divide two complex numbers.
2*d30dc8cbSJohn Marino
3*d30dc8cbSJohn Marino Copyright (C) 2002, 2003, 2004, 2005, 2008, 2009, 2010, 2011, 2012 INRIA
4*d30dc8cbSJohn Marino
5*d30dc8cbSJohn Marino This file is part of GNU MPC.
6*d30dc8cbSJohn Marino
7*d30dc8cbSJohn Marino GNU MPC is free software; you can redistribute it and/or modify it under
8*d30dc8cbSJohn Marino the terms of the GNU Lesser General Public License as published by the
9*d30dc8cbSJohn Marino Free Software Foundation; either version 3 of the License, or (at your
10*d30dc8cbSJohn Marino option) any later version.
11*d30dc8cbSJohn Marino
12*d30dc8cbSJohn Marino GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
13*d30dc8cbSJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14*d30dc8cbSJohn Marino FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15*d30dc8cbSJohn Marino more details.
16*d30dc8cbSJohn Marino
17*d30dc8cbSJohn Marino You should have received a copy of the GNU Lesser General Public License
18*d30dc8cbSJohn Marino along with this program. If not, see http://www.gnu.org/licenses/ .
19*d30dc8cbSJohn Marino */
20*d30dc8cbSJohn Marino
21*d30dc8cbSJohn Marino #include "mpc-impl.h"
22*d30dc8cbSJohn Marino
23*d30dc8cbSJohn Marino /* this routine deals with the case where w is zero */
24*d30dc8cbSJohn Marino static int
mpc_div_zero(mpc_ptr a,mpc_srcptr z,mpc_srcptr w,mpc_rnd_t rnd)25*d30dc8cbSJohn Marino mpc_div_zero (mpc_ptr a, mpc_srcptr z, mpc_srcptr w, mpc_rnd_t rnd)
26*d30dc8cbSJohn Marino /* Assumes w==0, implementation according to C99 G.5.1.8 */
27*d30dc8cbSJohn Marino {
28*d30dc8cbSJohn Marino int sign = MPFR_SIGNBIT (mpc_realref (w));
29*d30dc8cbSJohn Marino mpfr_t infty;
30*d30dc8cbSJohn Marino
31*d30dc8cbSJohn Marino mpfr_init2 (infty, MPFR_PREC_MIN);
32*d30dc8cbSJohn Marino mpfr_set_inf (infty, sign);
33*d30dc8cbSJohn Marino mpfr_mul (mpc_realref (a), infty, mpc_realref (z), MPC_RND_RE (rnd));
34*d30dc8cbSJohn Marino mpfr_mul (mpc_imagref (a), infty, mpc_imagref (z), MPC_RND_IM (rnd));
35*d30dc8cbSJohn Marino mpfr_clear (infty);
36*d30dc8cbSJohn Marino return MPC_INEX (0, 0); /* exact */
37*d30dc8cbSJohn Marino }
38*d30dc8cbSJohn Marino
39*d30dc8cbSJohn Marino /* this routine deals with the case where z is infinite and w finite */
40*d30dc8cbSJohn Marino static int
mpc_div_inf_fin(mpc_ptr rop,mpc_srcptr z,mpc_srcptr w)41*d30dc8cbSJohn Marino mpc_div_inf_fin (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w)
42*d30dc8cbSJohn Marino /* Assumes w finite and non-zero and z infinite; implementation
43*d30dc8cbSJohn Marino according to C99 G.5.1.8 */
44*d30dc8cbSJohn Marino {
45*d30dc8cbSJohn Marino int a, b, x, y;
46*d30dc8cbSJohn Marino
47*d30dc8cbSJohn Marino a = (mpfr_inf_p (mpc_realref (z)) ? MPFR_SIGNBIT (mpc_realref (z)) : 0);
48*d30dc8cbSJohn Marino b = (mpfr_inf_p (mpc_imagref (z)) ? MPFR_SIGNBIT (mpc_imagref (z)) : 0);
49*d30dc8cbSJohn Marino
50*d30dc8cbSJohn Marino /* a is -1 if Re(z) = -Inf, 1 if Re(z) = +Inf, 0 if Re(z) is finite
51*d30dc8cbSJohn Marino b is -1 if Im(z) = -Inf, 1 if Im(z) = +Inf, 0 if Im(z) is finite */
52*d30dc8cbSJohn Marino
53*d30dc8cbSJohn Marino /* x = MPC_MPFR_SIGN (a * mpc_realref (w) + b * mpc_imagref (w)) */
54*d30dc8cbSJohn Marino /* y = MPC_MPFR_SIGN (b * mpc_realref (w) - a * mpc_imagref (w)) */
55*d30dc8cbSJohn Marino if (a == 0 || b == 0) {
56*d30dc8cbSJohn Marino /* only one of a or b can be zero, since z is infinite */
57*d30dc8cbSJohn Marino x = a * MPC_MPFR_SIGN (mpc_realref (w)) + b * MPC_MPFR_SIGN (mpc_imagref (w));
58*d30dc8cbSJohn Marino y = b * MPC_MPFR_SIGN (mpc_realref (w)) - a * MPC_MPFR_SIGN (mpc_imagref (w));
59*d30dc8cbSJohn Marino }
60*d30dc8cbSJohn Marino else {
61*d30dc8cbSJohn Marino /* Both parts of z are infinite; x could be determined by sign
62*d30dc8cbSJohn Marino considerations and comparisons. Since operations with non-finite
63*d30dc8cbSJohn Marino numbers are not considered time-critical, we let mpfr do the work. */
64*d30dc8cbSJohn Marino mpfr_t sign;
65*d30dc8cbSJohn Marino
66*d30dc8cbSJohn Marino mpfr_init2 (sign, 2);
67*d30dc8cbSJohn Marino /* This is enough to determine the sign of sums and differences. */
68*d30dc8cbSJohn Marino
69*d30dc8cbSJohn Marino if (a == 1)
70*d30dc8cbSJohn Marino if (b == 1) {
71*d30dc8cbSJohn Marino mpfr_add (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
72*d30dc8cbSJohn Marino x = MPC_MPFR_SIGN (sign);
73*d30dc8cbSJohn Marino mpfr_sub (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
74*d30dc8cbSJohn Marino y = MPC_MPFR_SIGN (sign);
75*d30dc8cbSJohn Marino }
76*d30dc8cbSJohn Marino else { /* b == -1 */
77*d30dc8cbSJohn Marino mpfr_sub (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
78*d30dc8cbSJohn Marino x = MPC_MPFR_SIGN (sign);
79*d30dc8cbSJohn Marino mpfr_add (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
80*d30dc8cbSJohn Marino y = -MPC_MPFR_SIGN (sign);
81*d30dc8cbSJohn Marino }
82*d30dc8cbSJohn Marino else /* a == -1 */
83*d30dc8cbSJohn Marino if (b == 1) {
84*d30dc8cbSJohn Marino mpfr_sub (sign, mpc_imagref (w), mpc_realref (w), GMP_RNDN);
85*d30dc8cbSJohn Marino x = MPC_MPFR_SIGN (sign);
86*d30dc8cbSJohn Marino mpfr_add (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
87*d30dc8cbSJohn Marino y = MPC_MPFR_SIGN (sign);
88*d30dc8cbSJohn Marino }
89*d30dc8cbSJohn Marino else { /* b == -1 */
90*d30dc8cbSJohn Marino mpfr_add (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
91*d30dc8cbSJohn Marino x = -MPC_MPFR_SIGN (sign);
92*d30dc8cbSJohn Marino mpfr_sub (sign, mpc_imagref (w), mpc_realref (w), GMP_RNDN);
93*d30dc8cbSJohn Marino y = MPC_MPFR_SIGN (sign);
94*d30dc8cbSJohn Marino }
95*d30dc8cbSJohn Marino mpfr_clear (sign);
96*d30dc8cbSJohn Marino }
97*d30dc8cbSJohn Marino
98*d30dc8cbSJohn Marino if (x == 0)
99*d30dc8cbSJohn Marino mpfr_set_nan (mpc_realref (rop));
100*d30dc8cbSJohn Marino else
101*d30dc8cbSJohn Marino mpfr_set_inf (mpc_realref (rop), x);
102*d30dc8cbSJohn Marino if (y == 0)
103*d30dc8cbSJohn Marino mpfr_set_nan (mpc_imagref (rop));
104*d30dc8cbSJohn Marino else
105*d30dc8cbSJohn Marino mpfr_set_inf (mpc_imagref (rop), y);
106*d30dc8cbSJohn Marino
107*d30dc8cbSJohn Marino return MPC_INEX (0, 0); /* exact */
108*d30dc8cbSJohn Marino }
109*d30dc8cbSJohn Marino
110*d30dc8cbSJohn Marino
111*d30dc8cbSJohn Marino /* this routine deals with the case where z if finite and w infinite */
112*d30dc8cbSJohn Marino static int
mpc_div_fin_inf(mpc_ptr rop,mpc_srcptr z,mpc_srcptr w)113*d30dc8cbSJohn Marino mpc_div_fin_inf (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w)
114*d30dc8cbSJohn Marino /* Assumes z finite and w infinite; implementation according to
115*d30dc8cbSJohn Marino C99 G.5.1.8 */
116*d30dc8cbSJohn Marino {
117*d30dc8cbSJohn Marino mpfr_t c, d, a, b, x, y, zero;
118*d30dc8cbSJohn Marino
119*d30dc8cbSJohn Marino mpfr_init2 (c, 2); /* needed to hold a signed zero, +1 or -1 */
120*d30dc8cbSJohn Marino mpfr_init2 (d, 2);
121*d30dc8cbSJohn Marino mpfr_init2 (x, 2);
122*d30dc8cbSJohn Marino mpfr_init2 (y, 2);
123*d30dc8cbSJohn Marino mpfr_init2 (zero, 2);
124*d30dc8cbSJohn Marino mpfr_set_ui (zero, 0ul, GMP_RNDN);
125*d30dc8cbSJohn Marino mpfr_init2 (a, mpfr_get_prec (mpc_realref (z)));
126*d30dc8cbSJohn Marino mpfr_init2 (b, mpfr_get_prec (mpc_imagref (z)));
127*d30dc8cbSJohn Marino
128*d30dc8cbSJohn Marino mpfr_set_ui (c, (mpfr_inf_p (mpc_realref (w)) ? 1 : 0), GMP_RNDN);
129*d30dc8cbSJohn Marino MPFR_COPYSIGN (c, c, mpc_realref (w), GMP_RNDN);
130*d30dc8cbSJohn Marino mpfr_set_ui (d, (mpfr_inf_p (mpc_imagref (w)) ? 1 : 0), GMP_RNDN);
131*d30dc8cbSJohn Marino MPFR_COPYSIGN (d, d, mpc_imagref (w), GMP_RNDN);
132*d30dc8cbSJohn Marino
133*d30dc8cbSJohn Marino mpfr_mul (a, mpc_realref (z), c, GMP_RNDN); /* exact */
134*d30dc8cbSJohn Marino mpfr_mul (b, mpc_imagref (z), d, GMP_RNDN);
135*d30dc8cbSJohn Marino mpfr_add (x, a, b, GMP_RNDN);
136*d30dc8cbSJohn Marino
137*d30dc8cbSJohn Marino mpfr_mul (b, mpc_imagref (z), c, GMP_RNDN);
138*d30dc8cbSJohn Marino mpfr_mul (a, mpc_realref (z), d, GMP_RNDN);
139*d30dc8cbSJohn Marino mpfr_sub (y, b, a, GMP_RNDN);
140*d30dc8cbSJohn Marino
141*d30dc8cbSJohn Marino MPFR_COPYSIGN (mpc_realref (rop), zero, x, GMP_RNDN);
142*d30dc8cbSJohn Marino MPFR_COPYSIGN (mpc_imagref (rop), zero, y, GMP_RNDN);
143*d30dc8cbSJohn Marino
144*d30dc8cbSJohn Marino mpfr_clear (c);
145*d30dc8cbSJohn Marino mpfr_clear (d);
146*d30dc8cbSJohn Marino mpfr_clear (x);
147*d30dc8cbSJohn Marino mpfr_clear (y);
148*d30dc8cbSJohn Marino mpfr_clear (zero);
149*d30dc8cbSJohn Marino mpfr_clear (a);
150*d30dc8cbSJohn Marino mpfr_clear (b);
151*d30dc8cbSJohn Marino
152*d30dc8cbSJohn Marino return MPC_INEX (0, 0); /* exact */
153*d30dc8cbSJohn Marino }
154*d30dc8cbSJohn Marino
155*d30dc8cbSJohn Marino
156*d30dc8cbSJohn Marino static int
mpc_div_real(mpc_ptr rop,mpc_srcptr z,mpc_srcptr w,mpc_rnd_t rnd)157*d30dc8cbSJohn Marino mpc_div_real (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w, mpc_rnd_t rnd)
158*d30dc8cbSJohn Marino /* Assumes z finite and w finite and non-zero, with imaginary part
159*d30dc8cbSJohn Marino of w a signed zero. */
160*d30dc8cbSJohn Marino {
161*d30dc8cbSJohn Marino int inex_re, inex_im;
162*d30dc8cbSJohn Marino /* save signs of operands in case there are overlaps */
163*d30dc8cbSJohn Marino int zrs = MPFR_SIGNBIT (mpc_realref (z));
164*d30dc8cbSJohn Marino int zis = MPFR_SIGNBIT (mpc_imagref (z));
165*d30dc8cbSJohn Marino int wrs = MPFR_SIGNBIT (mpc_realref (w));
166*d30dc8cbSJohn Marino int wis = MPFR_SIGNBIT (mpc_imagref (w));
167*d30dc8cbSJohn Marino
168*d30dc8cbSJohn Marino /* warning: rop may overlap with z,w so treat the imaginary part first */
169*d30dc8cbSJohn Marino inex_im = mpfr_div (mpc_imagref(rop), mpc_imagref(z), mpc_realref(w), MPC_RND_IM(rnd));
170*d30dc8cbSJohn Marino inex_re = mpfr_div (mpc_realref(rop), mpc_realref(z), mpc_realref(w), MPC_RND_RE(rnd));
171*d30dc8cbSJohn Marino
172*d30dc8cbSJohn Marino /* correct signs of zeroes if necessary, which does not affect the
173*d30dc8cbSJohn Marino inexact flags */
174*d30dc8cbSJohn Marino if (mpfr_zero_p (mpc_realref (rop)))
175*d30dc8cbSJohn Marino mpfr_setsign (mpc_realref (rop), mpc_realref (rop), (zrs != wrs && zis != wis),
176*d30dc8cbSJohn Marino GMP_RNDN); /* exact */
177*d30dc8cbSJohn Marino if (mpfr_zero_p (mpc_imagref (rop)))
178*d30dc8cbSJohn Marino mpfr_setsign (mpc_imagref (rop), mpc_imagref (rop), (zis != wrs && zrs == wis),
179*d30dc8cbSJohn Marino GMP_RNDN);
180*d30dc8cbSJohn Marino
181*d30dc8cbSJohn Marino return MPC_INEX(inex_re, inex_im);
182*d30dc8cbSJohn Marino }
183*d30dc8cbSJohn Marino
184*d30dc8cbSJohn Marino
185*d30dc8cbSJohn Marino static int
mpc_div_imag(mpc_ptr rop,mpc_srcptr z,mpc_srcptr w,mpc_rnd_t rnd)186*d30dc8cbSJohn Marino mpc_div_imag (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w, mpc_rnd_t rnd)
187*d30dc8cbSJohn Marino /* Assumes z finite and w finite and non-zero, with real part
188*d30dc8cbSJohn Marino of w a signed zero. */
189*d30dc8cbSJohn Marino {
190*d30dc8cbSJohn Marino int inex_re, inex_im;
191*d30dc8cbSJohn Marino int overlap = (rop == z) || (rop == w);
192*d30dc8cbSJohn Marino int imag_z = mpfr_zero_p (mpc_realref (z));
193*d30dc8cbSJohn Marino mpfr_t wloc;
194*d30dc8cbSJohn Marino mpc_t tmprop;
195*d30dc8cbSJohn Marino mpc_ptr dest = (overlap) ? tmprop : rop;
196*d30dc8cbSJohn Marino /* save signs of operands in case there are overlaps */
197*d30dc8cbSJohn Marino int zrs = MPFR_SIGNBIT (mpc_realref (z));
198*d30dc8cbSJohn Marino int zis = MPFR_SIGNBIT (mpc_imagref (z));
199*d30dc8cbSJohn Marino int wrs = MPFR_SIGNBIT (mpc_realref (w));
200*d30dc8cbSJohn Marino int wis = MPFR_SIGNBIT (mpc_imagref (w));
201*d30dc8cbSJohn Marino
202*d30dc8cbSJohn Marino if (overlap)
203*d30dc8cbSJohn Marino mpc_init3 (tmprop, MPC_PREC_RE (rop), MPC_PREC_IM (rop));
204*d30dc8cbSJohn Marino
205*d30dc8cbSJohn Marino wloc[0] = mpc_imagref(w)[0]; /* copies mpfr struct IM(w) into wloc */
206*d30dc8cbSJohn Marino inex_re = mpfr_div (mpc_realref(dest), mpc_imagref(z), wloc, MPC_RND_RE(rnd));
207*d30dc8cbSJohn Marino mpfr_neg (wloc, wloc, GMP_RNDN);
208*d30dc8cbSJohn Marino /* changes the sign only in wloc, not in w; no need to correct later */
209*d30dc8cbSJohn Marino inex_im = mpfr_div (mpc_imagref(dest), mpc_realref(z), wloc, MPC_RND_IM(rnd));
210*d30dc8cbSJohn Marino
211*d30dc8cbSJohn Marino if (overlap) {
212*d30dc8cbSJohn Marino /* Note: we could use mpc_swap here, but this might cause problems
213*d30dc8cbSJohn Marino if rop and tmprop have been allocated using different methods, since
214*d30dc8cbSJohn Marino it will swap the significands of rop and tmprop. See
215*d30dc8cbSJohn Marino http://lists.gforge.inria.fr/pipermail/mpc-discuss/2009-August/000504.html */
216*d30dc8cbSJohn Marino mpc_set (rop, tmprop, MPC_RNDNN); /* exact */
217*d30dc8cbSJohn Marino mpc_clear (tmprop);
218*d30dc8cbSJohn Marino }
219*d30dc8cbSJohn Marino
220*d30dc8cbSJohn Marino /* correct signs of zeroes if necessary, which does not affect the
221*d30dc8cbSJohn Marino inexact flags */
222*d30dc8cbSJohn Marino if (mpfr_zero_p (mpc_realref (rop)))
223*d30dc8cbSJohn Marino mpfr_setsign (mpc_realref (rop), mpc_realref (rop), (zrs != wrs && zis != wis),
224*d30dc8cbSJohn Marino GMP_RNDN); /* exact */
225*d30dc8cbSJohn Marino if (imag_z)
226*d30dc8cbSJohn Marino mpfr_setsign (mpc_imagref (rop), mpc_imagref (rop), (zis != wrs && zrs == wis),
227*d30dc8cbSJohn Marino GMP_RNDN);
228*d30dc8cbSJohn Marino
229*d30dc8cbSJohn Marino return MPC_INEX(inex_re, inex_im);
230*d30dc8cbSJohn Marino }
231*d30dc8cbSJohn Marino
232*d30dc8cbSJohn Marino
233*d30dc8cbSJohn Marino int
mpc_div(mpc_ptr a,mpc_srcptr b,mpc_srcptr c,mpc_rnd_t rnd)234*d30dc8cbSJohn Marino mpc_div (mpc_ptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
235*d30dc8cbSJohn Marino {
236*d30dc8cbSJohn Marino int ok_re = 0, ok_im = 0;
237*d30dc8cbSJohn Marino mpc_t res, c_conj;
238*d30dc8cbSJohn Marino mpfr_t q;
239*d30dc8cbSJohn Marino mpfr_prec_t prec;
240*d30dc8cbSJohn Marino int inex, inexact_prod, inexact_norm, inexact_re, inexact_im, loops = 0;
241*d30dc8cbSJohn Marino int underflow_norm, overflow_norm, underflow_prod, overflow_prod;
242*d30dc8cbSJohn Marino int underflow_re = 0, overflow_re = 0, underflow_im = 0, overflow_im = 0;
243*d30dc8cbSJohn Marino mpfr_rnd_t rnd_re = MPC_RND_RE (rnd), rnd_im = MPC_RND_IM (rnd);
244*d30dc8cbSJohn Marino int saved_underflow, saved_overflow;
245*d30dc8cbSJohn Marino int tmpsgn;
246*d30dc8cbSJohn Marino
247*d30dc8cbSJohn Marino /* According to the C standard G.3, there are three types of numbers: */
248*d30dc8cbSJohn Marino /* finite (both parts are usual real numbers; contains 0), infinite */
249*d30dc8cbSJohn Marino /* (at least one part is a real infinity) and all others; the latter */
250*d30dc8cbSJohn Marino /* are numbers containing a nan, but no infinity, and could reasonably */
251*d30dc8cbSJohn Marino /* be called nan. */
252*d30dc8cbSJohn Marino /* By G.5.1.4, infinite/finite=infinite; finite/infinite=0; */
253*d30dc8cbSJohn Marino /* all other divisions that are not finite/finite return nan+i*nan. */
254*d30dc8cbSJohn Marino /* Division by 0 could be handled by the following case of division by */
255*d30dc8cbSJohn Marino /* a real; we handle it separately instead. */
256*d30dc8cbSJohn Marino if (mpc_zero_p (c))
257*d30dc8cbSJohn Marino return mpc_div_zero (a, b, c, rnd);
258*d30dc8cbSJohn Marino else if (mpc_inf_p (b) && mpc_fin_p (c))
259*d30dc8cbSJohn Marino return mpc_div_inf_fin (a, b, c);
260*d30dc8cbSJohn Marino else if (mpc_fin_p (b) && mpc_inf_p (c))
261*d30dc8cbSJohn Marino return mpc_div_fin_inf (a, b, c);
262*d30dc8cbSJohn Marino else if (!mpc_fin_p (b) || !mpc_fin_p (c)) {
263*d30dc8cbSJohn Marino mpc_set_nan (a);
264*d30dc8cbSJohn Marino return MPC_INEX (0, 0);
265*d30dc8cbSJohn Marino }
266*d30dc8cbSJohn Marino else if (mpfr_zero_p(mpc_imagref(c)))
267*d30dc8cbSJohn Marino return mpc_div_real (a, b, c, rnd);
268*d30dc8cbSJohn Marino else if (mpfr_zero_p(mpc_realref(c)))
269*d30dc8cbSJohn Marino return mpc_div_imag (a, b, c, rnd);
270*d30dc8cbSJohn Marino
271*d30dc8cbSJohn Marino prec = MPC_MAX_PREC(a);
272*d30dc8cbSJohn Marino
273*d30dc8cbSJohn Marino mpc_init2 (res, 2);
274*d30dc8cbSJohn Marino mpfr_init (q);
275*d30dc8cbSJohn Marino
276*d30dc8cbSJohn Marino /* create the conjugate of c in c_conj without allocating new memory */
277*d30dc8cbSJohn Marino mpc_realref (c_conj)[0] = mpc_realref (c)[0];
278*d30dc8cbSJohn Marino mpc_imagref (c_conj)[0] = mpc_imagref (c)[0];
279*d30dc8cbSJohn Marino MPFR_CHANGE_SIGN (mpc_imagref (c_conj));
280*d30dc8cbSJohn Marino
281*d30dc8cbSJohn Marino /* save the underflow or overflow flags from MPFR */
282*d30dc8cbSJohn Marino saved_underflow = mpfr_underflow_p ();
283*d30dc8cbSJohn Marino saved_overflow = mpfr_overflow_p ();
284*d30dc8cbSJohn Marino
285*d30dc8cbSJohn Marino do {
286*d30dc8cbSJohn Marino loops ++;
287*d30dc8cbSJohn Marino prec += loops <= 2 ? mpc_ceil_log2 (prec) + 5 : prec / 2;
288*d30dc8cbSJohn Marino
289*d30dc8cbSJohn Marino mpc_set_prec (res, prec);
290*d30dc8cbSJohn Marino mpfr_set_prec (q, prec);
291*d30dc8cbSJohn Marino
292*d30dc8cbSJohn Marino /* first compute norm(c) */
293*d30dc8cbSJohn Marino mpfr_clear_underflow ();
294*d30dc8cbSJohn Marino mpfr_clear_overflow ();
295*d30dc8cbSJohn Marino inexact_norm = mpc_norm (q, c, GMP_RNDU);
296*d30dc8cbSJohn Marino underflow_norm = mpfr_underflow_p ();
297*d30dc8cbSJohn Marino overflow_norm = mpfr_overflow_p ();
298*d30dc8cbSJohn Marino if (underflow_norm)
299*d30dc8cbSJohn Marino mpfr_set_ui (q, 0ul, GMP_RNDN);
300*d30dc8cbSJohn Marino /* to obtain divisions by 0 later on */
301*d30dc8cbSJohn Marino
302*d30dc8cbSJohn Marino /* now compute b*conjugate(c) */
303*d30dc8cbSJohn Marino mpfr_clear_underflow ();
304*d30dc8cbSJohn Marino mpfr_clear_overflow ();
305*d30dc8cbSJohn Marino inexact_prod = mpc_mul (res, b, c_conj, MPC_RNDZZ);
306*d30dc8cbSJohn Marino inexact_re = MPC_INEX_RE (inexact_prod);
307*d30dc8cbSJohn Marino inexact_im = MPC_INEX_IM (inexact_prod);
308*d30dc8cbSJohn Marino underflow_prod = mpfr_underflow_p ();
309*d30dc8cbSJohn Marino overflow_prod = mpfr_overflow_p ();
310*d30dc8cbSJohn Marino /* unfortunately, does not distinguish between under-/overflow
311*d30dc8cbSJohn Marino in real or imaginary parts
312*d30dc8cbSJohn Marino hopefully, the side-effects of mpc_mul do indeed raise the
313*d30dc8cbSJohn Marino mpfr exceptions */
314*d30dc8cbSJohn Marino if (overflow_prod) {
315*d30dc8cbSJohn Marino int isinf = 0;
316*d30dc8cbSJohn Marino tmpsgn = mpfr_sgn (mpc_realref(res));
317*d30dc8cbSJohn Marino if (tmpsgn > 0)
318*d30dc8cbSJohn Marino {
319*d30dc8cbSJohn Marino mpfr_nextabove (mpc_realref(res));
320*d30dc8cbSJohn Marino isinf = mpfr_inf_p (mpc_realref(res));
321*d30dc8cbSJohn Marino mpfr_nextbelow (mpc_realref(res));
322*d30dc8cbSJohn Marino }
323*d30dc8cbSJohn Marino else if (tmpsgn < 0)
324*d30dc8cbSJohn Marino {
325*d30dc8cbSJohn Marino mpfr_nextbelow (mpc_realref(res));
326*d30dc8cbSJohn Marino isinf = mpfr_inf_p (mpc_realref(res));
327*d30dc8cbSJohn Marino mpfr_nextabove (mpc_realref(res));
328*d30dc8cbSJohn Marino }
329*d30dc8cbSJohn Marino if (isinf)
330*d30dc8cbSJohn Marino {
331*d30dc8cbSJohn Marino mpfr_set_inf (mpc_realref(res), tmpsgn);
332*d30dc8cbSJohn Marino overflow_re = 1;
333*d30dc8cbSJohn Marino }
334*d30dc8cbSJohn Marino tmpsgn = mpfr_sgn (mpc_imagref(res));
335*d30dc8cbSJohn Marino isinf = 0;
336*d30dc8cbSJohn Marino if (tmpsgn > 0)
337*d30dc8cbSJohn Marino {
338*d30dc8cbSJohn Marino mpfr_nextabove (mpc_imagref(res));
339*d30dc8cbSJohn Marino isinf = mpfr_inf_p (mpc_imagref(res));
340*d30dc8cbSJohn Marino mpfr_nextbelow (mpc_imagref(res));
341*d30dc8cbSJohn Marino }
342*d30dc8cbSJohn Marino else if (tmpsgn < 0)
343*d30dc8cbSJohn Marino {
344*d30dc8cbSJohn Marino mpfr_nextbelow (mpc_imagref(res));
345*d30dc8cbSJohn Marino isinf = mpfr_inf_p (mpc_imagref(res));
346*d30dc8cbSJohn Marino mpfr_nextabove (mpc_imagref(res));
347*d30dc8cbSJohn Marino }
348*d30dc8cbSJohn Marino if (isinf)
349*d30dc8cbSJohn Marino {
350*d30dc8cbSJohn Marino mpfr_set_inf (mpc_imagref(res), tmpsgn);
351*d30dc8cbSJohn Marino overflow_im = 1;
352*d30dc8cbSJohn Marino }
353*d30dc8cbSJohn Marino mpc_set (a, res, rnd);
354*d30dc8cbSJohn Marino goto end;
355*d30dc8cbSJohn Marino }
356*d30dc8cbSJohn Marino
357*d30dc8cbSJohn Marino /* divide the product by the norm */
358*d30dc8cbSJohn Marino if (inexact_norm == 0 && (inexact_re == 0 || inexact_im == 0)) {
359*d30dc8cbSJohn Marino /* The division has good chances to be exact in at least one part. */
360*d30dc8cbSJohn Marino /* Since this can cause problems when not rounding to the nearest, */
361*d30dc8cbSJohn Marino /* we use the division code of mpfr, which handles the situation. */
362*d30dc8cbSJohn Marino mpfr_clear_underflow ();
363*d30dc8cbSJohn Marino mpfr_clear_overflow ();
364*d30dc8cbSJohn Marino inexact_re |= mpfr_div (mpc_realref (res), mpc_realref (res), q, GMP_RNDZ);
365*d30dc8cbSJohn Marino underflow_re = mpfr_underflow_p ();
366*d30dc8cbSJohn Marino overflow_re = mpfr_overflow_p ();
367*d30dc8cbSJohn Marino ok_re = !inexact_re || underflow_re || overflow_re
368*d30dc8cbSJohn Marino || mpfr_can_round (mpc_realref (res), prec - 4, GMP_RNDN,
369*d30dc8cbSJohn Marino GMP_RNDZ, MPC_PREC_RE(a) + (rnd_re == GMP_RNDN));
370*d30dc8cbSJohn Marino
371*d30dc8cbSJohn Marino if (ok_re) /* compute imaginary part */ {
372*d30dc8cbSJohn Marino mpfr_clear_underflow ();
373*d30dc8cbSJohn Marino mpfr_clear_overflow ();
374*d30dc8cbSJohn Marino inexact_im |= mpfr_div (mpc_imagref (res), mpc_imagref (res), q, GMP_RNDZ);
375*d30dc8cbSJohn Marino underflow_im = mpfr_underflow_p ();
376*d30dc8cbSJohn Marino overflow_im = mpfr_overflow_p ();
377*d30dc8cbSJohn Marino ok_im = !inexact_im || underflow_im || overflow_im
378*d30dc8cbSJohn Marino || mpfr_can_round (mpc_imagref (res), prec - 4, GMP_RNDN,
379*d30dc8cbSJohn Marino GMP_RNDZ, MPC_PREC_IM(a) + (rnd_im == GMP_RNDN));
380*d30dc8cbSJohn Marino }
381*d30dc8cbSJohn Marino }
382*d30dc8cbSJohn Marino else {
383*d30dc8cbSJohn Marino /* The division is inexact, so for efficiency reasons we invert q */
384*d30dc8cbSJohn Marino /* only once and multiply by the inverse. */
385*d30dc8cbSJohn Marino if (mpfr_ui_div (q, 1ul, q, GMP_RNDZ) || inexact_norm) {
386*d30dc8cbSJohn Marino /* if 1/q is inexact, the approximations of the real and
387*d30dc8cbSJohn Marino imaginary part below will be inexact, unless RE(res)
388*d30dc8cbSJohn Marino or IM(res) is zero */
389*d30dc8cbSJohn Marino inexact_re |= ~mpfr_zero_p (mpc_realref (res));
390*d30dc8cbSJohn Marino inexact_im |= ~mpfr_zero_p (mpc_imagref (res));
391*d30dc8cbSJohn Marino }
392*d30dc8cbSJohn Marino mpfr_clear_underflow ();
393*d30dc8cbSJohn Marino mpfr_clear_overflow ();
394*d30dc8cbSJohn Marino inexact_re |= mpfr_mul (mpc_realref (res), mpc_realref (res), q, GMP_RNDZ);
395*d30dc8cbSJohn Marino underflow_re = mpfr_underflow_p ();
396*d30dc8cbSJohn Marino overflow_re = mpfr_overflow_p ();
397*d30dc8cbSJohn Marino ok_re = !inexact_re || underflow_re || overflow_re
398*d30dc8cbSJohn Marino || mpfr_can_round (mpc_realref (res), prec - 4, GMP_RNDN,
399*d30dc8cbSJohn Marino GMP_RNDZ, MPC_PREC_RE(a) + (rnd_re == GMP_RNDN));
400*d30dc8cbSJohn Marino
401*d30dc8cbSJohn Marino if (ok_re) /* compute imaginary part */ {
402*d30dc8cbSJohn Marino mpfr_clear_underflow ();
403*d30dc8cbSJohn Marino mpfr_clear_overflow ();
404*d30dc8cbSJohn Marino inexact_im |= mpfr_mul (mpc_imagref (res), mpc_imagref (res), q, GMP_RNDZ);
405*d30dc8cbSJohn Marino underflow_im = mpfr_underflow_p ();
406*d30dc8cbSJohn Marino overflow_im = mpfr_overflow_p ();
407*d30dc8cbSJohn Marino ok_im = !inexact_im || underflow_im || overflow_im
408*d30dc8cbSJohn Marino || mpfr_can_round (mpc_imagref (res), prec - 4, GMP_RNDN,
409*d30dc8cbSJohn Marino GMP_RNDZ, MPC_PREC_IM(a) + (rnd_im == GMP_RNDN));
410*d30dc8cbSJohn Marino }
411*d30dc8cbSJohn Marino }
412*d30dc8cbSJohn Marino } while ((!ok_re || !ok_im) && !underflow_norm && !overflow_norm
413*d30dc8cbSJohn Marino && !underflow_prod && !overflow_prod);
414*d30dc8cbSJohn Marino
415*d30dc8cbSJohn Marino inex = mpc_set (a, res, rnd);
416*d30dc8cbSJohn Marino inexact_re = MPC_INEX_RE (inex);
417*d30dc8cbSJohn Marino inexact_im = MPC_INEX_IM (inex);
418*d30dc8cbSJohn Marino
419*d30dc8cbSJohn Marino end:
420*d30dc8cbSJohn Marino /* fix values and inexact flags in case of overflow/underflow */
421*d30dc8cbSJohn Marino /* FIXME: heuristic, certainly does not cover all cases */
422*d30dc8cbSJohn Marino if (overflow_re || (underflow_norm && !underflow_prod)) {
423*d30dc8cbSJohn Marino mpfr_set_inf (mpc_realref (a), mpfr_sgn (mpc_realref (res)));
424*d30dc8cbSJohn Marino inexact_re = mpfr_sgn (mpc_realref (res));
425*d30dc8cbSJohn Marino }
426*d30dc8cbSJohn Marino else if (underflow_re || (overflow_norm && !overflow_prod)) {
427*d30dc8cbSJohn Marino inexact_re = mpfr_signbit (mpc_realref (res)) ? 1 : -1;
428*d30dc8cbSJohn Marino mpfr_set_zero (mpc_realref (a), -inexact_re);
429*d30dc8cbSJohn Marino }
430*d30dc8cbSJohn Marino if (overflow_im || (underflow_norm && !underflow_prod)) {
431*d30dc8cbSJohn Marino mpfr_set_inf (mpc_imagref (a), mpfr_sgn (mpc_imagref (res)));
432*d30dc8cbSJohn Marino inexact_im = mpfr_sgn (mpc_imagref (res));
433*d30dc8cbSJohn Marino }
434*d30dc8cbSJohn Marino else if (underflow_im || (overflow_norm && !overflow_prod)) {
435*d30dc8cbSJohn Marino inexact_im = mpfr_signbit (mpc_imagref (res)) ? 1 : -1;
436*d30dc8cbSJohn Marino mpfr_set_zero (mpc_imagref (a), -inexact_im);
437*d30dc8cbSJohn Marino }
438*d30dc8cbSJohn Marino
439*d30dc8cbSJohn Marino mpc_clear (res);
440*d30dc8cbSJohn Marino mpfr_clear (q);
441*d30dc8cbSJohn Marino
442*d30dc8cbSJohn Marino /* restore underflow and overflow flags from MPFR */
443*d30dc8cbSJohn Marino if (saved_underflow)
444*d30dc8cbSJohn Marino mpfr_set_underflow ();
445*d30dc8cbSJohn Marino if (saved_overflow)
446*d30dc8cbSJohn Marino mpfr_set_overflow ();
447*d30dc8cbSJohn Marino
448*d30dc8cbSJohn Marino return MPC_INEX (inexact_re, inexact_im);
449*d30dc8cbSJohn Marino }
450