xref: /dflybsd-src/contrib/mpfr/src/pow_z.c (revision 2786097444a0124b5d33763854de247e230c6629)
14a238c70SJohn Marino /* mpfr_pow_z -- power function x^z with z a MPZ
24a238c70SJohn Marino 
3*ab6d115fSJohn Marino Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
4*ab6d115fSJohn Marino Contributed by the AriC and Caramel projects, INRIA.
54a238c70SJohn Marino 
64a238c70SJohn Marino This file is part of the GNU MPFR Library.
74a238c70SJohn Marino 
84a238c70SJohn Marino The GNU MPFR Library is free software; you can redistribute it and/or modify
94a238c70SJohn Marino it under the terms of the GNU Lesser General Public License as published by
104a238c70SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
114a238c70SJohn Marino option) any later version.
124a238c70SJohn Marino 
134a238c70SJohn Marino The GNU MPFR Library is distributed in the hope that it will be useful, but
144a238c70SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
154a238c70SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
164a238c70SJohn Marino License for more details.
174a238c70SJohn Marino 
184a238c70SJohn Marino You should have received a copy of the GNU Lesser General Public License
194a238c70SJohn Marino along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
204a238c70SJohn Marino http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
214a238c70SJohn Marino 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
224a238c70SJohn Marino 
234a238c70SJohn Marino #define MPFR_NEED_LONGLONG_H
244a238c70SJohn Marino #include "mpfr-impl.h"
254a238c70SJohn Marino 
264a238c70SJohn Marino /* y <- x^|z| with z != 0
274a238c70SJohn Marino    if cr=1: ensures correct rounding of y
284a238c70SJohn Marino    if cr=0: does not ensure correct rounding, but avoid spurious overflow
294a238c70SJohn Marino    or underflow, and uses the precision of y as working precision (warning,
304a238c70SJohn Marino    y and x might be the same variable). */
314a238c70SJohn Marino static int
mpfr_pow_pos_z(mpfr_ptr y,mpfr_srcptr x,mpz_srcptr z,mpfr_rnd_t rnd,int cr)324a238c70SJohn Marino mpfr_pow_pos_z (mpfr_ptr y, mpfr_srcptr x, mpz_srcptr z, mpfr_rnd_t rnd, int cr)
334a238c70SJohn Marino {
344a238c70SJohn Marino   mpfr_t res;
354a238c70SJohn Marino   mpfr_prec_t prec, err;
364a238c70SJohn Marino   int inexact;
374a238c70SJohn Marino   mpfr_rnd_t rnd1, rnd2;
384a238c70SJohn Marino   mpz_t absz;
394a238c70SJohn Marino   mp_size_t size_z;
404a238c70SJohn Marino   MPFR_ZIV_DECL (loop);
414a238c70SJohn Marino   MPFR_BLOCK_DECL (flags);
424a238c70SJohn Marino 
434a238c70SJohn Marino   MPFR_LOG_FUNC
444a238c70SJohn Marino     (("x[%Pu]=%.*Rg z=%Zd rnd=%d cr=%d",
454a238c70SJohn Marino       mpfr_get_prec (x), mpfr_log_prec, x, z, rnd, cr),
464a238c70SJohn Marino      ("y[%Pu]=%.*Rg inexact=%d",
474a238c70SJohn Marino       mpfr_get_prec (y), mpfr_log_prec, y, inexact));
484a238c70SJohn Marino 
494a238c70SJohn Marino   MPFR_ASSERTD (mpz_sgn (z) != 0);
504a238c70SJohn Marino 
514a238c70SJohn Marino   if (MPFR_UNLIKELY (mpz_cmpabs_ui (z, 1) == 0))
524a238c70SJohn Marino     return mpfr_set (y, x, rnd);
534a238c70SJohn Marino 
544a238c70SJohn Marino   absz[0] = z[0];
554a238c70SJohn Marino   SIZ (absz) = ABS(SIZ(absz)); /* Hack to get abs(z) */
564a238c70SJohn Marino   MPFR_MPZ_SIZEINBASE2 (size_z, z);
574a238c70SJohn Marino 
584a238c70SJohn Marino   /* round toward 1 (or -1) to avoid spurious overflow or underflow,
594a238c70SJohn Marino      i.e. if an overflow or underflow occurs, it is a real exception
604a238c70SJohn Marino      and is not just due to the rounding error. */
614a238c70SJohn Marino   rnd1 = (MPFR_EXP(x) >= 1) ? MPFR_RNDZ
624a238c70SJohn Marino     : (MPFR_IS_POS(x) ? MPFR_RNDU : MPFR_RNDD);
634a238c70SJohn Marino   rnd2 = (MPFR_EXP(x) >= 1) ? MPFR_RNDD : MPFR_RNDU;
644a238c70SJohn Marino 
654a238c70SJohn Marino   if (cr != 0)
664a238c70SJohn Marino     prec = MPFR_PREC (y) + 3 + size_z + MPFR_INT_CEIL_LOG2 (MPFR_PREC (y));
674a238c70SJohn Marino   else
684a238c70SJohn Marino     prec = MPFR_PREC (y);
694a238c70SJohn Marino   mpfr_init2 (res, prec);
704a238c70SJohn Marino 
714a238c70SJohn Marino   MPFR_ZIV_INIT (loop, prec);
724a238c70SJohn Marino   for (;;)
734a238c70SJohn Marino     {
744a238c70SJohn Marino       unsigned int inexmul;  /* will be non-zero if res may be inexact */
754a238c70SJohn Marino       mp_size_t i = size_z;
764a238c70SJohn Marino 
774a238c70SJohn Marino       /* now 2^(i-1) <= z < 2^i */
784a238c70SJohn Marino       /* see below (case z < 0) for the error analysis, which is identical,
794a238c70SJohn Marino          except if z=n, the maximal relative error is here 2(n-1)2^(-prec)
804a238c70SJohn Marino          instead of 2(2n-1)2^(-prec) for z<0. */
814a238c70SJohn Marino       MPFR_ASSERTD (prec > (mpfr_prec_t) i);
824a238c70SJohn Marino       err = prec - 1 - (mpfr_prec_t) i;
834a238c70SJohn Marino 
844a238c70SJohn Marino       MPFR_BLOCK (flags,
854a238c70SJohn Marino                   inexmul = mpfr_mul (res, x, x, rnd2);
864a238c70SJohn Marino                   MPFR_ASSERTD (i >= 2);
874a238c70SJohn Marino                   if (mpz_tstbit (absz, i - 2))
884a238c70SJohn Marino                     inexmul |= mpfr_mul (res, res, x, rnd1);
894a238c70SJohn Marino                   for (i -= 3; i >= 0 && !MPFR_BLOCK_EXCEP; i--)
904a238c70SJohn Marino                     {
914a238c70SJohn Marino                       inexmul |= mpfr_mul (res, res, res, rnd2);
924a238c70SJohn Marino                       if (mpz_tstbit (absz, i))
934a238c70SJohn Marino                         inexmul |= mpfr_mul (res, res, x, rnd1);
944a238c70SJohn Marino                     });
954a238c70SJohn Marino       if (MPFR_LIKELY (inexmul == 0 || cr == 0
964a238c70SJohn Marino                        || MPFR_OVERFLOW (flags) || MPFR_UNDERFLOW (flags)
974a238c70SJohn Marino                        || MPFR_CAN_ROUND (res, err, MPFR_PREC (y), rnd)))
984a238c70SJohn Marino         break;
994a238c70SJohn Marino       /* Can't decide correct rounding, increase the precision */
1004a238c70SJohn Marino       MPFR_ZIV_NEXT (loop, prec);
1014a238c70SJohn Marino       mpfr_set_prec (res, prec);
1024a238c70SJohn Marino     }
1034a238c70SJohn Marino   MPFR_ZIV_FREE (loop);
1044a238c70SJohn Marino 
1054a238c70SJohn Marino   /* Check Overflow */
1064a238c70SJohn Marino   if (MPFR_OVERFLOW (flags))
1074a238c70SJohn Marino     {
1084a238c70SJohn Marino       MPFR_LOG_MSG (("overflow\n", 0));
1094a238c70SJohn Marino       inexact = mpfr_overflow (y, rnd, mpz_odd_p (absz) ?
1104a238c70SJohn Marino                                MPFR_SIGN (x) : MPFR_SIGN_POS);
1114a238c70SJohn Marino     }
1124a238c70SJohn Marino   /* Check Underflow */
1134a238c70SJohn Marino   else if (MPFR_UNDERFLOW (flags))
1144a238c70SJohn Marino     {
1154a238c70SJohn Marino       MPFR_LOG_MSG (("underflow\n", 0));
1164a238c70SJohn Marino       if (rnd == MPFR_RNDN)
1174a238c70SJohn Marino         {
1184a238c70SJohn Marino           mpfr_t y2, zz;
1194a238c70SJohn Marino 
1204a238c70SJohn Marino           /* We cannot decide now whether the result should be rounded
1214a238c70SJohn Marino              toward zero or +Inf. So, let's use the general case of
1224a238c70SJohn Marino              mpfr_pow, which can do that. But the problem is that the
1234a238c70SJohn Marino              result can be exact! However, it is sufficient to try to
1244a238c70SJohn Marino              round on 2 bits (the precision does not matter in case of
1254a238c70SJohn Marino              underflow, since MPFR does not have subnormals), in which
1264a238c70SJohn Marino              case, the result cannot be exact due to previous filtering
1274a238c70SJohn Marino              of trivial cases. */
1284a238c70SJohn Marino           MPFR_ASSERTD (mpfr_cmp_si_2exp (x, MPFR_SIGN (x),
1294a238c70SJohn Marino                                           MPFR_EXP (x) - 1) != 0);
1304a238c70SJohn Marino           mpfr_init2 (y2, 2);
1314a238c70SJohn Marino           mpfr_init2 (zz, ABS (SIZ (z)) * GMP_NUMB_BITS);
1324a238c70SJohn Marino           inexact = mpfr_set_z (zz, z, MPFR_RNDN);
1334a238c70SJohn Marino           MPFR_ASSERTN (inexact == 0);
1344a238c70SJohn Marino           inexact = mpfr_pow_general (y2, x, zz, rnd, 1,
1354a238c70SJohn Marino                                       (mpfr_save_expo_t *) NULL);
1364a238c70SJohn Marino           mpfr_clear (zz);
1374a238c70SJohn Marino           mpfr_set (y, y2, MPFR_RNDN);
1384a238c70SJohn Marino           mpfr_clear (y2);
1394a238c70SJohn Marino           __gmpfr_flags = MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW;
1404a238c70SJohn Marino         }
1414a238c70SJohn Marino       else
1424a238c70SJohn Marino         {
1434a238c70SJohn Marino           inexact = mpfr_underflow (y, rnd, mpz_odd_p (absz) ?
1444a238c70SJohn Marino                                     MPFR_SIGN (x) : MPFR_SIGN_POS);
1454a238c70SJohn Marino         }
1464a238c70SJohn Marino     }
1474a238c70SJohn Marino   else
1484a238c70SJohn Marino     inexact = mpfr_set (y, res, rnd);
1494a238c70SJohn Marino 
1504a238c70SJohn Marino   mpfr_clear (res);
1514a238c70SJohn Marino   return inexact;
1524a238c70SJohn Marino }
1534a238c70SJohn Marino 
1544a238c70SJohn Marino /* The computation of y = pow(x,z) is done by
1554a238c70SJohn Marino  *    y = set_ui(1)      if z = 0
1564a238c70SJohn Marino  *    y = pow_ui(x,z)    if z > 0
1574a238c70SJohn Marino  *    y = pow_ui(1/x,-z) if z < 0
1584a238c70SJohn Marino  *
1594a238c70SJohn Marino  * Note: in case z < 0, we could also compute 1/pow_ui(x,-z). However, in
1604a238c70SJohn Marino  * case MAX < 1/MIN, where MAX is the largest positive value, i.e.,
1614a238c70SJohn Marino  * MAX = nextbelow(+Inf), and MIN is the smallest positive value, i.e.,
1624a238c70SJohn Marino  * MIN = nextabove(+0), then x^(-z) might produce an overflow, whereas
1634a238c70SJohn Marino  * x^z is representable.
1644a238c70SJohn Marino  */
1654a238c70SJohn Marino 
1664a238c70SJohn Marino int
mpfr_pow_z(mpfr_ptr y,mpfr_srcptr x,mpz_srcptr z,mpfr_rnd_t rnd)1674a238c70SJohn Marino mpfr_pow_z (mpfr_ptr y, mpfr_srcptr x, mpz_srcptr z, mpfr_rnd_t rnd)
1684a238c70SJohn Marino {
1694a238c70SJohn Marino   int   inexact;
1704a238c70SJohn Marino   mpz_t tmp;
1714a238c70SJohn Marino   MPFR_SAVE_EXPO_DECL (expo);
1724a238c70SJohn Marino 
1734a238c70SJohn Marino   MPFR_LOG_FUNC
1744a238c70SJohn Marino     (("x[%Pu]=%.*Rg z=%Zd rnd=%d",
1754a238c70SJohn Marino       mpfr_get_prec (x), mpfr_log_prec, x, z, rnd),
1764a238c70SJohn Marino      ("y[%Pu]=%.*Rg inexact=%d",
1774a238c70SJohn Marino       mpfr_get_prec (y), mpfr_log_prec, y, inexact));
1784a238c70SJohn Marino 
1794a238c70SJohn Marino   /* x^0 = 1 for any x, even a NaN */
1804a238c70SJohn Marino   if (MPFR_UNLIKELY (mpz_sgn (z) == 0))
1814a238c70SJohn Marino     return mpfr_set_ui (y, 1, rnd);
1824a238c70SJohn Marino 
1834a238c70SJohn Marino   if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
1844a238c70SJohn Marino     {
1854a238c70SJohn Marino       if (MPFR_IS_NAN (x))
1864a238c70SJohn Marino         {
1874a238c70SJohn Marino           MPFR_SET_NAN (y);
1884a238c70SJohn Marino           MPFR_RET_NAN;
1894a238c70SJohn Marino         }
1904a238c70SJohn Marino       else if (MPFR_IS_INF (x))
1914a238c70SJohn Marino         {
1924a238c70SJohn Marino           /* Inf^n = Inf, (-Inf)^n = Inf for n even, -Inf for n odd */
1934a238c70SJohn Marino           /* Inf ^(-n) = 0, sign = + if x>0 or z even */
1944a238c70SJohn Marino           if (mpz_sgn (z) > 0)
1954a238c70SJohn Marino             MPFR_SET_INF (y);
1964a238c70SJohn Marino           else
1974a238c70SJohn Marino             MPFR_SET_ZERO (y);
1984a238c70SJohn Marino           if (MPFR_UNLIKELY (MPFR_IS_NEG (x) && mpz_odd_p (z)))
1994a238c70SJohn Marino             MPFR_SET_NEG (y);
2004a238c70SJohn Marino           else
2014a238c70SJohn Marino             MPFR_SET_POS (y);
2024a238c70SJohn Marino           MPFR_RET (0);
2034a238c70SJohn Marino         }
2044a238c70SJohn Marino       else /* x is zero */
2054a238c70SJohn Marino         {
2064a238c70SJohn Marino           MPFR_ASSERTD (MPFR_IS_ZERO(x));
2074a238c70SJohn Marino           if (mpz_sgn (z) > 0)
2084a238c70SJohn Marino             /* 0^n = +/-0 for any n */
2094a238c70SJohn Marino             MPFR_SET_ZERO (y);
2104a238c70SJohn Marino           else
2114a238c70SJohn Marino             {
2124a238c70SJohn Marino               /* 0^(-n) if +/- INF */
2134a238c70SJohn Marino               MPFR_SET_INF (y);
2144a238c70SJohn Marino               mpfr_set_divby0 ();
2154a238c70SJohn Marino             }
2164a238c70SJohn Marino           if (MPFR_LIKELY (MPFR_IS_POS (x) || mpz_even_p (z)))
2174a238c70SJohn Marino             MPFR_SET_POS (y);
2184a238c70SJohn Marino           else
2194a238c70SJohn Marino             MPFR_SET_NEG (y);
2204a238c70SJohn Marino           MPFR_RET(0);
2214a238c70SJohn Marino         }
2224a238c70SJohn Marino     }
2234a238c70SJohn Marino 
2244a238c70SJohn Marino   MPFR_SAVE_EXPO_MARK (expo);
2254a238c70SJohn Marino 
2264a238c70SJohn Marino   /* detect exact powers: x^-n is exact iff x is a power of 2
2274a238c70SJohn Marino      Do it if n > 0 too as this is faster and this filtering is
2284a238c70SJohn Marino      needed in case of underflow. */
2294a238c70SJohn Marino   if (MPFR_UNLIKELY (mpfr_cmp_si_2exp (x, MPFR_SIGN (x),
2304a238c70SJohn Marino                                        MPFR_EXP (x) - 1) == 0))
2314a238c70SJohn Marino     {
2324a238c70SJohn Marino       mpfr_exp_t expx = MPFR_EXP (x); /* warning: x and y may be the same
2334a238c70SJohn Marino                                          variable */
2344a238c70SJohn Marino 
2354a238c70SJohn Marino       MPFR_LOG_MSG (("x^n with x power of two\n", 0));
2364a238c70SJohn Marino       mpfr_set_si (y, mpz_odd_p (z) ? MPFR_INT_SIGN(x) : 1, rnd);
2374a238c70SJohn Marino       MPFR_ASSERTD (MPFR_IS_FP (y));
2384a238c70SJohn Marino       mpz_init (tmp);
2394a238c70SJohn Marino       mpz_mul_si (tmp, z, expx - 1);
2404a238c70SJohn Marino       MPFR_ASSERTD (MPFR_GET_EXP (y) == 1);
2414a238c70SJohn Marino       mpz_add_ui (tmp, tmp, 1);
2424a238c70SJohn Marino       inexact = 0;
2434a238c70SJohn Marino       if (MPFR_UNLIKELY (mpz_cmp_si (tmp, __gmpfr_emin) < 0))
2444a238c70SJohn Marino         {
2454a238c70SJohn Marino           MPFR_LOG_MSG (("underflow\n", 0));
2464a238c70SJohn Marino           /* |y| is a power of two, thus |y| <= 2^(emin-2), and in
2474a238c70SJohn Marino              rounding to nearest, the value must be rounded to 0. */
2484a238c70SJohn Marino           if (rnd == MPFR_RNDN)
2494a238c70SJohn Marino             rnd = MPFR_RNDZ;
2504a238c70SJohn Marino           inexact = mpfr_underflow (y, rnd, MPFR_SIGN (y));
2514a238c70SJohn Marino         }
2524a238c70SJohn Marino       else if (MPFR_UNLIKELY (mpz_cmp_si (tmp, __gmpfr_emax) > 0))
2534a238c70SJohn Marino         {
2544a238c70SJohn Marino           MPFR_LOG_MSG (("overflow\n", 0));
2554a238c70SJohn Marino           inexact = mpfr_overflow (y, rnd, MPFR_SIGN (y));
2564a238c70SJohn Marino         }
2574a238c70SJohn Marino       else
2584a238c70SJohn Marino         MPFR_SET_EXP (y, mpz_get_si (tmp));
2594a238c70SJohn Marino       mpz_clear (tmp);
2604a238c70SJohn Marino       MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, __gmpfr_flags);
2614a238c70SJohn Marino     }
2624a238c70SJohn Marino   else if (mpz_sgn (z) > 0)
2634a238c70SJohn Marino     {
2644a238c70SJohn Marino       inexact = mpfr_pow_pos_z (y, x, z, rnd, 1);
2654a238c70SJohn Marino       MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, __gmpfr_flags);
2664a238c70SJohn Marino     }
2674a238c70SJohn Marino   else
2684a238c70SJohn Marino     {
2694a238c70SJohn Marino       /* Declaration of the intermediary variable */
2704a238c70SJohn Marino       mpfr_t t;
2714a238c70SJohn Marino       mpfr_prec_t Nt;   /* Precision of the intermediary variable */
2724a238c70SJohn Marino       mpfr_rnd_t rnd1;
2734a238c70SJohn Marino       mp_size_t size_z;
2744a238c70SJohn Marino       MPFR_ZIV_DECL (loop);
2754a238c70SJohn Marino 
2764a238c70SJohn Marino       MPFR_MPZ_SIZEINBASE2 (size_z, z);
2774a238c70SJohn Marino 
2784a238c70SJohn Marino       /* initial working precision */
2794a238c70SJohn Marino       Nt = MPFR_PREC (y);
2804a238c70SJohn Marino       Nt = Nt + size_z + 3 + MPFR_INT_CEIL_LOG2 (Nt);
2814a238c70SJohn Marino       /* ensures Nt >= bits(z)+2 */
2824a238c70SJohn Marino 
2834a238c70SJohn Marino       /* initialise of intermediary variable */
2844a238c70SJohn Marino       mpfr_init2 (t, Nt);
2854a238c70SJohn Marino 
2864a238c70SJohn Marino       /* We will compute rnd(rnd1(1/x) ^ (-z)), where rnd1 is the rounding
2874a238c70SJohn Marino          toward sign(x), to avoid spurious overflow or underflow. */
2884a238c70SJohn Marino       rnd1 = MPFR_EXP (x) < 1 ? MPFR_RNDZ :
2894a238c70SJohn Marino         (MPFR_SIGN (x) > 0 ? MPFR_RNDU : MPFR_RNDD);
2904a238c70SJohn Marino 
2914a238c70SJohn Marino       MPFR_ZIV_INIT (loop, Nt);
2924a238c70SJohn Marino       for (;;)
2934a238c70SJohn Marino         {
2944a238c70SJohn Marino           MPFR_BLOCK_DECL (flags);
2954a238c70SJohn Marino 
2964a238c70SJohn Marino           /* compute (1/x)^(-z), -z>0 */
2974a238c70SJohn Marino           /* As emin = -emax, an underflow cannot occur in the division.
2984a238c70SJohn Marino              And if an overflow occurs, then this means that x^z overflows
2994a238c70SJohn Marino              too (since we have rounded toward 1 or -1). */
3004a238c70SJohn Marino           MPFR_BLOCK (flags, mpfr_ui_div (t, 1, x, rnd1));
3014a238c70SJohn Marino           MPFR_ASSERTD (! MPFR_UNDERFLOW (flags));
3024a238c70SJohn Marino           /* t = (1/x)*(1+theta) where |theta| <= 2^(-Nt) */
3034a238c70SJohn Marino           if (MPFR_UNLIKELY (MPFR_OVERFLOW (flags)))
3044a238c70SJohn Marino             goto overflow;
3054a238c70SJohn Marino           MPFR_BLOCK (flags, mpfr_pow_pos_z (t, t, z, rnd, 0));
3064a238c70SJohn Marino           /* Now if z=-n, t = x^z*(1+theta)^(2n-1) where |theta| <= 2^(-Nt),
3074a238c70SJohn Marino              with theta maybe different from above. If (2n-1)*2^(-Nt) <= 1/2,
3084a238c70SJohn Marino              which is satisfied as soon as Nt >= bits(z)+2, then we can use
3094a238c70SJohn Marino              Lemma \ref{lemma_graillat} from algorithms.tex, which yields
3104a238c70SJohn Marino              t = x^z*(1+theta) with |theta| <= 2(2n-1)*2^(-Nt), thus the
3114a238c70SJohn Marino              error is bounded by 2(2n-1) ulps <= 2^(bits(z)+2) ulps. */
3124a238c70SJohn Marino           if (MPFR_UNLIKELY (MPFR_OVERFLOW (flags)))
3134a238c70SJohn Marino             {
3144a238c70SJohn Marino             overflow:
3154a238c70SJohn Marino               MPFR_ZIV_FREE (loop);
3164a238c70SJohn Marino               mpfr_clear (t);
3174a238c70SJohn Marino               MPFR_SAVE_EXPO_FREE (expo);
3184a238c70SJohn Marino               MPFR_LOG_MSG (("overflow\n", 0));
3194a238c70SJohn Marino               return mpfr_overflow (y, rnd,
3204a238c70SJohn Marino                                     mpz_odd_p (z) ? MPFR_SIGN (x) :
3214a238c70SJohn Marino                                     MPFR_SIGN_POS);
3224a238c70SJohn Marino             }
3234a238c70SJohn Marino           if (MPFR_UNLIKELY (MPFR_UNDERFLOW (flags)))
3244a238c70SJohn Marino             {
3254a238c70SJohn Marino               MPFR_ZIV_FREE (loop);
3264a238c70SJohn Marino               mpfr_clear (t);
3274a238c70SJohn Marino               MPFR_LOG_MSG (("underflow\n", 0));
3284a238c70SJohn Marino               if (rnd == MPFR_RNDN)
3294a238c70SJohn Marino                 {
3304a238c70SJohn Marino                   mpfr_t y2, zz;
3314a238c70SJohn Marino 
3324a238c70SJohn Marino                   /* We cannot decide now whether the result should be
3334a238c70SJohn Marino                      rounded toward zero or away from zero. So, like
3344a238c70SJohn Marino                      in mpfr_pow_pos_z, let's use the general case of
3354a238c70SJohn Marino                      mpfr_pow in precision 2. */
3364a238c70SJohn Marino                   MPFR_ASSERTD (mpfr_cmp_si_2exp (x, MPFR_SIGN (x),
3374a238c70SJohn Marino                                                   MPFR_EXP (x) - 1) != 0);
3384a238c70SJohn Marino                   mpfr_init2 (y2, 2);
3394a238c70SJohn Marino                   mpfr_init2 (zz, ABS (SIZ (z)) * GMP_NUMB_BITS);
3404a238c70SJohn Marino                   inexact = mpfr_set_z (zz, z, MPFR_RNDN);
3414a238c70SJohn Marino                   MPFR_ASSERTN (inexact == 0);
3424a238c70SJohn Marino                   inexact = mpfr_pow_general (y2, x, zz, rnd, 1,
3434a238c70SJohn Marino                                               (mpfr_save_expo_t *) NULL);
3444a238c70SJohn Marino                   mpfr_clear (zz);
3454a238c70SJohn Marino                   mpfr_set (y, y2, MPFR_RNDN);
3464a238c70SJohn Marino                   mpfr_clear (y2);
3474a238c70SJohn Marino                   MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, MPFR_FLAGS_UNDERFLOW);
3484a238c70SJohn Marino                   goto end;
3494a238c70SJohn Marino                 }
3504a238c70SJohn Marino               else
3514a238c70SJohn Marino                 {
3524a238c70SJohn Marino                   MPFR_SAVE_EXPO_FREE (expo);
3534a238c70SJohn Marino                   return mpfr_underflow (y, rnd, mpz_odd_p (z) ?
3544a238c70SJohn Marino                                          MPFR_SIGN (x) : MPFR_SIGN_POS);
3554a238c70SJohn Marino                 }
3564a238c70SJohn Marino             }
3574a238c70SJohn Marino           if (MPFR_LIKELY (MPFR_CAN_ROUND (t, Nt - size_z - 2, MPFR_PREC (y),
3584a238c70SJohn Marino                                            rnd)))
3594a238c70SJohn Marino             break;
3604a238c70SJohn Marino           /* actualisation of the precision */
3614a238c70SJohn Marino           MPFR_ZIV_NEXT (loop, Nt);
3624a238c70SJohn Marino           mpfr_set_prec (t, Nt);
3634a238c70SJohn Marino         }
3644a238c70SJohn Marino       MPFR_ZIV_FREE (loop);
3654a238c70SJohn Marino 
3664a238c70SJohn Marino       inexact = mpfr_set (y, t, rnd);
3674a238c70SJohn Marino       mpfr_clear (t);
3684a238c70SJohn Marino     }
3694a238c70SJohn Marino 
3704a238c70SJohn Marino  end:
3714a238c70SJohn Marino   MPFR_SAVE_EXPO_FREE (expo);
3724a238c70SJohn Marino   return mpfr_check_range (y, inexact, rnd);
3734a238c70SJohn Marino }
374