xref: /dragonfly/contrib/mpc/src/pow_ui.c (revision d30dc8cb)
1*d30dc8cbSJohn Marino /* mpc_pow_ui -- Raise a complex number to an integer power.
2*d30dc8cbSJohn Marino 
3*d30dc8cbSJohn Marino Copyright (C) 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 <limits.h> /* for CHAR_BIT */
22*d30dc8cbSJohn Marino #include "mpc-impl.h"
23*d30dc8cbSJohn Marino 
24*d30dc8cbSJohn Marino static int
mpc_pow_usi_naive(mpc_ptr z,mpc_srcptr x,unsigned long y,int sign,mpc_rnd_t rnd)25*d30dc8cbSJohn Marino mpc_pow_usi_naive (mpc_ptr z, mpc_srcptr x, unsigned long y, int sign,
26*d30dc8cbSJohn Marino    mpc_rnd_t rnd)
27*d30dc8cbSJohn Marino {
28*d30dc8cbSJohn Marino    int inex;
29*d30dc8cbSJohn Marino    mpc_t t;
30*d30dc8cbSJohn Marino 
31*d30dc8cbSJohn Marino    mpc_init3 (t, sizeof (unsigned long) * CHAR_BIT, MPFR_PREC_MIN);
32*d30dc8cbSJohn Marino    if (sign > 0)
33*d30dc8cbSJohn Marino       mpc_set_ui (t, y, MPC_RNDNN); /* exact */
34*d30dc8cbSJohn Marino    else
35*d30dc8cbSJohn Marino       mpc_set_si (t, - (signed long) y, MPC_RNDNN);
36*d30dc8cbSJohn Marino    inex = mpc_pow (z, x, t, rnd);
37*d30dc8cbSJohn Marino    mpc_clear (t);
38*d30dc8cbSJohn Marino 
39*d30dc8cbSJohn Marino    return inex;
40*d30dc8cbSJohn Marino }
41*d30dc8cbSJohn Marino 
42*d30dc8cbSJohn Marino 
43*d30dc8cbSJohn Marino int
mpc_pow_usi(mpc_ptr z,mpc_srcptr x,unsigned long y,int sign,mpc_rnd_t rnd)44*d30dc8cbSJohn Marino mpc_pow_usi (mpc_ptr z, mpc_srcptr x, unsigned long y, int sign,
45*d30dc8cbSJohn Marino    mpc_rnd_t rnd)
46*d30dc8cbSJohn Marino    /* computes z = x^(sign*y) */
47*d30dc8cbSJohn Marino {
48*d30dc8cbSJohn Marino    int inex;
49*d30dc8cbSJohn Marino    mpc_t t, x3;
50*d30dc8cbSJohn Marino    mpfr_prec_t p, l, l0;
51*d30dc8cbSJohn Marino    long unsigned int u;
52*d30dc8cbSJohn Marino    int has3; /* non-zero if y has '11' in its binary representation */
53*d30dc8cbSJohn Marino    int loop, done;
54*d30dc8cbSJohn Marino 
55*d30dc8cbSJohn Marino    /* let mpc_pow deal with special values */
56*d30dc8cbSJohn Marino    if (!mpc_fin_p (x) || mpfr_zero_p (mpc_realref (x)) || mpfr_zero_p (mpc_imagref(x))
57*d30dc8cbSJohn Marino        || y == 0)
58*d30dc8cbSJohn Marino       return mpc_pow_usi_naive (z, x, y, sign, rnd);
59*d30dc8cbSJohn Marino    /* easy special cases */
60*d30dc8cbSJohn Marino    else if (y == 1) {
61*d30dc8cbSJohn Marino       if (sign > 0)
62*d30dc8cbSJohn Marino          return mpc_set (z, x, rnd);
63*d30dc8cbSJohn Marino       else
64*d30dc8cbSJohn Marino          return mpc_ui_div (z, 1ul, x, rnd);
65*d30dc8cbSJohn Marino    }
66*d30dc8cbSJohn Marino    else if (y == 2 && sign > 0)
67*d30dc8cbSJohn Marino       return mpc_sqr (z, x, rnd);
68*d30dc8cbSJohn Marino    /* let mpc_pow treat potential over- and underflows */
69*d30dc8cbSJohn Marino    else {
70*d30dc8cbSJohn Marino       mpfr_exp_t exp_r = mpfr_get_exp (mpc_realref (x)),
71*d30dc8cbSJohn Marino                  exp_i = mpfr_get_exp (mpc_imagref (x));
72*d30dc8cbSJohn Marino       if (   MPC_MAX (exp_r, exp_i) > mpfr_get_emax () / (mpfr_exp_t) y
73*d30dc8cbSJohn Marino              /* heuristic for overflow */
74*d30dc8cbSJohn Marino           || MPC_MAX (-exp_r, -exp_i) > (-mpfr_get_emin ()) / (mpfr_exp_t) y
75*d30dc8cbSJohn Marino              /* heuristic for underflow */
76*d30dc8cbSJohn Marino          )
77*d30dc8cbSJohn Marino          return mpc_pow_usi_naive (z, x, y, sign, rnd);
78*d30dc8cbSJohn Marino    }
79*d30dc8cbSJohn Marino 
80*d30dc8cbSJohn Marino    has3 = (y & (y >> 1)) != 0;
81*d30dc8cbSJohn Marino    for (l = 0, u = y; u > 3; l ++, u >>= 1);
82*d30dc8cbSJohn Marino    /* l>0 is the number of bits of y, minus 2, thus y has bits:
83*d30dc8cbSJohn Marino       y_{l+1} y_l y_{l-1} ... y_1 y_0 */
84*d30dc8cbSJohn Marino    l0 = l + 2;
85*d30dc8cbSJohn Marino    p = MPC_MAX_PREC(z) + l0 + 32; /* l0 ensures that y*2^{-p} <= 1 below */
86*d30dc8cbSJohn Marino    mpc_init2 (t, p);
87*d30dc8cbSJohn Marino    if (has3)
88*d30dc8cbSJohn Marino       mpc_init2 (x3, p);
89*d30dc8cbSJohn Marino 
90*d30dc8cbSJohn Marino    loop = 0;
91*d30dc8cbSJohn Marino    done = 0;
92*d30dc8cbSJohn Marino    while (!done) {
93*d30dc8cbSJohn Marino       loop++;
94*d30dc8cbSJohn Marino 
95*d30dc8cbSJohn Marino       mpc_sqr (t, x, MPC_RNDNN);
96*d30dc8cbSJohn Marino       if (has3) {
97*d30dc8cbSJohn Marino          mpc_mul (x3, t, x, MPC_RNDNN);
98*d30dc8cbSJohn Marino          if ((y >> l) & 1) /* y starts with 11... */
99*d30dc8cbSJohn Marino             mpc_set (t, x3, MPC_RNDNN);
100*d30dc8cbSJohn Marino       }
101*d30dc8cbSJohn Marino       while (l-- > 0) {
102*d30dc8cbSJohn Marino          mpc_sqr (t, t, MPC_RNDNN);
103*d30dc8cbSJohn Marino          if ((y >> l) & 1) {
104*d30dc8cbSJohn Marino             if ((l > 0) && ((y >> (l-1)) & 1)) /* implies has3 <> 0 */ {
105*d30dc8cbSJohn Marino                l--;
106*d30dc8cbSJohn Marino                mpc_sqr (t, t, MPC_RNDNN);
107*d30dc8cbSJohn Marino                mpc_mul (t, t, x3, MPC_RNDNN);
108*d30dc8cbSJohn Marino             }
109*d30dc8cbSJohn Marino             else
110*d30dc8cbSJohn Marino                mpc_mul (t, t, x, MPC_RNDNN);
111*d30dc8cbSJohn Marino          }
112*d30dc8cbSJohn Marino       }
113*d30dc8cbSJohn Marino       if (sign < 0)
114*d30dc8cbSJohn Marino          mpc_ui_div (t, 1ul, t, MPC_RNDNN);
115*d30dc8cbSJohn Marino 
116*d30dc8cbSJohn Marino       if (mpfr_zero_p (mpc_realref(t)) || mpfr_zero_p (mpc_imagref(t))) {
117*d30dc8cbSJohn Marino          inex = mpc_pow_usi_naive (z, x, y, sign, rnd);
118*d30dc8cbSJohn Marino             /* since mpfr_get_exp() is not defined for zero */
119*d30dc8cbSJohn Marino          done = 1;
120*d30dc8cbSJohn Marino       }
121*d30dc8cbSJohn Marino       else {
122*d30dc8cbSJohn Marino          /* see error bound in algorithms.tex; we use y<2^l0 instead of y-1
123*d30dc8cbSJohn Marino             also when sign>0                                                */
124*d30dc8cbSJohn Marino          mpfr_exp_t diff;
125*d30dc8cbSJohn Marino          mpfr_prec_t er, ei;
126*d30dc8cbSJohn Marino 
127*d30dc8cbSJohn Marino          diff = mpfr_get_exp (mpc_realref(t)) - mpfr_get_exp (mpc_imagref(t));
128*d30dc8cbSJohn Marino          /* the factor on the real part is 2+2^(-diff+2) <= 4 for diff >= 1
129*d30dc8cbSJohn Marino             and < 2^(-diff+3) for diff <= 0 */
130*d30dc8cbSJohn Marino          er = (diff >= 1) ? l0 + 3 : l0 + (-diff) + 3;
131*d30dc8cbSJohn Marino          /* the factor on the imaginary part is 2+2^(diff+2) <= 4 for diff <= -1
132*d30dc8cbSJohn Marino             and < 2^(diff+3) for diff >= 0 */
133*d30dc8cbSJohn Marino          ei = (diff <= -1) ? l0 + 3 : l0 + diff + 3;
134*d30dc8cbSJohn Marino          if (mpfr_can_round (mpc_realref(t), p - er, GMP_RNDN, GMP_RNDZ,
135*d30dc8cbSJohn Marino                               MPC_PREC_RE(z) + (MPC_RND_RE(rnd) == GMP_RNDN))
136*d30dc8cbSJohn Marino                && mpfr_can_round (mpc_imagref(t), p - ei, GMP_RNDN, GMP_RNDZ,
137*d30dc8cbSJohn Marino                               MPC_PREC_IM(z) + (MPC_RND_IM(rnd) == GMP_RNDN))) {
138*d30dc8cbSJohn Marino             inex = mpc_set (z, t, rnd);
139*d30dc8cbSJohn Marino             done = 1;
140*d30dc8cbSJohn Marino          }
141*d30dc8cbSJohn Marino          else if (loop == 1 && SAFE_ABS(mpfr_prec_t, diff) < MPC_MAX_PREC(z)) {
142*d30dc8cbSJohn Marino             /* common case, make a second trial at higher precision */
143*d30dc8cbSJohn Marino             p += MPC_MAX_PREC(x);
144*d30dc8cbSJohn Marino             mpc_set_prec (t, p);
145*d30dc8cbSJohn Marino             if (has3)
146*d30dc8cbSJohn Marino                mpc_set_prec (x3, p);
147*d30dc8cbSJohn Marino             l = l0 - 2;
148*d30dc8cbSJohn Marino          }
149*d30dc8cbSJohn Marino          else {
150*d30dc8cbSJohn Marino             /* stop the loop and use mpc_pow */
151*d30dc8cbSJohn Marino             inex = mpc_pow_usi_naive (z, x, y, sign, rnd);
152*d30dc8cbSJohn Marino             done = 1;
153*d30dc8cbSJohn Marino          }
154*d30dc8cbSJohn Marino       }
155*d30dc8cbSJohn Marino    }
156*d30dc8cbSJohn Marino 
157*d30dc8cbSJohn Marino    mpc_clear (t);
158*d30dc8cbSJohn Marino    if (has3)
159*d30dc8cbSJohn Marino       mpc_clear (x3);
160*d30dc8cbSJohn Marino 
161*d30dc8cbSJohn Marino    return inex;
162*d30dc8cbSJohn Marino }
163*d30dc8cbSJohn Marino 
164*d30dc8cbSJohn Marino 
165*d30dc8cbSJohn Marino int
mpc_pow_ui(mpc_ptr z,mpc_srcptr x,unsigned long y,mpc_rnd_t rnd)166*d30dc8cbSJohn Marino mpc_pow_ui (mpc_ptr z, mpc_srcptr x, unsigned long y, mpc_rnd_t rnd)
167*d30dc8cbSJohn Marino {
168*d30dc8cbSJohn Marino   return mpc_pow_usi (z, x, y, 1, rnd);
169*d30dc8cbSJohn Marino }
170