xref: /dflybsd-src/contrib/mpc/src/div.c (revision 04febcfb30580676d3e95f58a16c5137ee478b32)
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