diff options
author | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2010-08-17 09:10:13 +0000 |
---|---|---|
committer | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2010-08-17 09:10:13 +0000 |
commit | c9583bdfe064e1069828e518533f7bc29a8fdddb (patch) | |
tree | 2400842d4095628b8486fbeabaf7bc7b8af4ed02 /pow.c | |
parent | 50ac5b5985174201c7fa6e20496cd2b096107001 (diff) | |
download | mpfr-c9583bdfe064e1069828e518533f7bc29a8fdddb.tar.gz |
Source reorganization. In short:
* Added directories and moved related files into them:
- src for the MPFR source files (to build the library).
- doc for documentation files (except INSTALL, README...).
- tools for various tools (scripts) and mbench.
- tune for tuneup-related source files.
- other for other source files (not distributed in tarballs).
Existing directories:
- tests for the source files of the test suite (make check).
- examples for examples.
- m4 for m4 files.
* Renamed configure.in to configure.ac.
* Added/updated Makefile.am files where needed.
* Updated acinclude.m4 and configure.ac (AC_CONFIG_FILES line).
* Updated the documentation (INSTALL, README, doc/README.dev and
doc/mpfr.texi).
* Updated NEWS and TODO.
* Updated the scripts now in tools.
The following script was used:
#!/usr/bin/env zsh
svn mkdir doc other src tools tune
svn mv ${${(M)$(sed -n '/libmpfr_la_SOURCES/,/[^\]$/p' \
Makefile.am):#*.[ch]}:#get_patches.c} mparam_h.in \
round_raw_generic.c jyn_asympt.c src
svn mv mbench check_inits_clears coverage get_patches.sh mpfrlint \
nightly-test update-patchv update-version tools
svn mv bidimensional_sample.c speed.c tuneup.c tune
svn mv *.{c,h} other
svn mv FAQ.html README.dev algorithm* faq.xsl fdl.texi mpfr.texi \
update-faq doc
svn mv configure.in configure.ac
svn cp Makefile.am src/Makefile.am
svn rm replace_all
[Modifying some files, see above]
svn add doc/Makefile.am
svn add tune/Makefile.am
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@7087 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'pow.c')
-rw-r--r-- | pow.c | 675 |
1 files changed, 0 insertions, 675 deletions
diff --git a/pow.c b/pow.c deleted file mode 100644 index ac806ac63..000000000 --- a/pow.c +++ /dev/null @@ -1,675 +0,0 @@ -/* mpfr_pow -- power function x^y - -Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. -Contributed by the Arenaire and Caramel projects, INRIA. - -This file is part of the GNU MPFR Library. - -The GNU MPFR Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -The GNU MPFR Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see -http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., -51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ - -#define MPFR_NEED_LONGLONG_H -#include "mpfr-impl.h" - -/* return non zero iff x^y is exact. - Assumes x and y are ordinary numbers, - y is not an integer, x is not a power of 2 and x is positive - - If x^y is exact, it computes it and sets *inexact. -*/ -static int -mpfr_pow_is_exact (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, - mpfr_rnd_t rnd_mode, int *inexact) -{ - mpz_t a, c; - mpfr_exp_t d, b; - unsigned long i; - int res; - - MPFR_ASSERTD (!MPFR_IS_SINGULAR (y)); - MPFR_ASSERTD (!MPFR_IS_SINGULAR (x)); - MPFR_ASSERTD (!mpfr_integer_p (y)); - MPFR_ASSERTD (mpfr_cmp_si_2exp (x, MPFR_INT_SIGN (x), - MPFR_GET_EXP (x) - 1) != 0); - MPFR_ASSERTD (MPFR_IS_POS (x)); - - if (MPFR_IS_NEG (y)) - return 0; /* x is not a power of two => x^-y is not exact */ - - /* compute d such that y = c*2^d with c odd integer */ - mpz_init (c); - d = mpfr_get_z_2exp (c, y); - i = mpz_scan1 (c, 0); - mpz_fdiv_q_2exp (c, c, i); - d += i; - /* now y=c*2^d with c odd */ - /* Since y is not an integer, d is necessarily < 0 */ - MPFR_ASSERTD (d < 0); - - /* Compute a,b such that x=a*2^b */ - mpz_init (a); - b = mpfr_get_z_2exp (a, x); - i = mpz_scan1 (a, 0); - mpz_fdiv_q_2exp (a, a, i); - b += i; - /* now x=a*2^b with a is odd */ - - for (res = 1 ; d != 0 ; d++) - { - /* a*2^b is a square iff - (i) a is a square when b is even - (ii) 2*a is a square when b is odd */ - if (b % 2 != 0) - { - mpz_mul_2exp (a, a, 1); /* 2*a */ - b --; - } - MPFR_ASSERTD ((b % 2) == 0); - if (!mpz_perfect_square_p (a)) - { - res = 0; - goto end; - } - mpz_sqrt (a, a); - b = b / 2; - } - /* Now x = (a'*2^b')^(2^-d) with d < 0 - so x^y = ((a'*2^b')^(2^-d))^(c*2^d) - = ((a'*2^b')^c with c odd integer */ - { - mpfr_t tmp; - mpfr_prec_t p; - MPFR_MPZ_SIZEINBASE2 (p, a); - mpfr_init2 (tmp, p); /* prec = 1 should not be possible */ - res = mpfr_set_z (tmp, a, MPFR_RNDN); - MPFR_ASSERTD (res == 0); - res = mpfr_mul_2si (tmp, tmp, b, MPFR_RNDN); - MPFR_ASSERTD (res == 0); - *inexact = mpfr_pow_z (z, tmp, c, rnd_mode); - mpfr_clear (tmp); - res = 1; - } - end: - mpz_clear (a); - mpz_clear (c); - return res; -} - -/* Return 1 if y is an odd integer, 0 otherwise. */ -static int -is_odd (mpfr_srcptr y) -{ - mpfr_exp_t expo; - mpfr_prec_t prec; - mp_size_t yn; - mp_limb_t *yp; - - /* NAN, INF or ZERO are not allowed */ - MPFR_ASSERTD (!MPFR_IS_SINGULAR (y)); - - expo = MPFR_GET_EXP (y); - if (expo <= 0) - return 0; /* |y| < 1 and not 0 */ - - prec = MPFR_PREC(y); - if ((mpfr_prec_t) expo > prec) - return 0; /* y is a multiple of 2^(expo-prec), thus not odd */ - - /* 0 < expo <= prec: - y = 1xxxxxxxxxt.zzzzzzzzzzzzzzzzzz[000] - expo bits (prec-expo) bits - - We have to check that: - (a) the bit 't' is set - (b) all the 'z' bits are zero - */ - - prec = ((prec - 1) / GMP_NUMB_BITS + 1) * GMP_NUMB_BITS - expo; - /* number of z+0 bits */ - - yn = prec / GMP_NUMB_BITS; - MPFR_ASSERTN(yn >= 0); - /* yn is the index of limb containing the 't' bit */ - - yp = MPFR_MANT(y); - /* if expo is a multiple of GMP_NUMB_BITS, t is bit 0 */ - if (expo % GMP_NUMB_BITS == 0 ? (yp[yn] & 1) == 0 - : yp[yn] << ((expo % GMP_NUMB_BITS) - 1) != MPFR_LIMB_HIGHBIT) - return 0; - while (--yn >= 0) - if (yp[yn] != 0) - return 0; - return 1; -} - -/* Assumes that the exponent range has already been extended and if y is - an integer, then the result is not exact in unbounded exponent range. */ -int -mpfr_pow_general (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, - mpfr_rnd_t rnd_mode, int y_is_integer, mpfr_save_expo_t *expo) -{ - mpfr_t t, u, k, absx; - int k_non_zero = 0; - int check_exact_case = 0; - int inexact; - /* Declaration of the size variable */ - mpfr_prec_t Nz = MPFR_PREC(z); /* target precision */ - mpfr_prec_t Nt; /* working precision */ - mpfr_exp_t err; /* error */ - MPFR_ZIV_DECL (ziv_loop); - - - MPFR_LOG_FUNC (("x[%#R]=%R y[%#R]=%R rnd=%d", x, x, y, y, rnd_mode), - ("z[%#R]=%R inexact=%d", z, z, inexact)); - - /* We put the absolute value of x in absx, pointing to the significand - of x to avoid allocating memory for the significand of absx. */ - MPFR_ALIAS(absx, x, /*sign=*/ 1, /*EXP=*/ MPFR_EXP(x)); - - /* We will compute the absolute value of the result. So, let's - invert the rounding mode if the result is negative. */ - if (MPFR_IS_NEG (x) && is_odd (y)) - rnd_mode = MPFR_INVERT_RND (rnd_mode); - - /* compute the precision of intermediary variable */ - /* the optimal number of bits : see algorithms.tex */ - Nt = Nz + 5 + MPFR_INT_CEIL_LOG2 (Nz); - - /* initialise of intermediary variable */ - mpfr_init2 (t, Nt); - - MPFR_ZIV_INIT (ziv_loop, Nt); - for (;;) - { - MPFR_BLOCK_DECL (flags1); - - /* compute exp(y*ln|x|), using MPFR_RNDU to get an upper bound, so - that we can detect underflows. */ - mpfr_log (t, absx, MPFR_IS_NEG (y) ? MPFR_RNDD : MPFR_RNDU); /* ln|x| */ - mpfr_mul (t, y, t, MPFR_RNDU); /* y*ln|x| */ - if (k_non_zero) - { - MPFR_LOG_MSG (("subtract k * ln(2)\n", 0)); - mpfr_const_log2 (u, MPFR_RNDD); - mpfr_mul (u, u, k, MPFR_RNDD); - /* Error on u = k * log(2): < k * 2^(-Nt) < 1. */ - mpfr_sub (t, t, u, MPFR_RNDU); - MPFR_LOG_MSG (("t = y * ln|x| - k * ln(2)\n", 0)); - MPFR_LOG_VAR (t); - } - /* estimate of the error -- see pow function in algorithms.tex. - The error on t is at most 1/2 + 3*2^(EXP(t)+1) ulps, which is - <= 2^(EXP(t)+3) for EXP(t) >= -1, and <= 2 ulps for EXP(t) <= -2. - Additional error if k_no_zero: treal = t * errk, with - 1 - |k| * 2^(-Nt) <= exp(-|k| * 2^(-Nt)) <= errk <= 1, - i.e., additional absolute error <= 2^(EXP(k)+EXP(t)-Nt). - Total error <= 2^err1 + 2^err2 <= 2^(max(err1,err2)+1). */ - err = MPFR_NOTZERO (t) && MPFR_GET_EXP (t) >= -1 ? - MPFR_GET_EXP (t) + 3 : 1; - if (k_non_zero) - { - if (MPFR_GET_EXP (k) > err) - err = MPFR_GET_EXP (k); - err++; - } - MPFR_BLOCK (flags1, mpfr_exp (t, t, MPFR_RNDN)); /* exp(y*ln|x|)*/ - /* We need to test */ - if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (t) || MPFR_UNDERFLOW (flags1))) - { - mpfr_prec_t Ntmin; - MPFR_BLOCK_DECL (flags2); - - MPFR_ASSERTN (!k_non_zero); - MPFR_ASSERTN (!MPFR_IS_NAN (t)); - - /* Real underflow? */ - if (MPFR_IS_ZERO (t)) - { - /* Underflow. We computed rndn(exp(t)), where t >= y*ln|x|. - Therefore rndn(|x|^y) = 0, and we have a real underflow on - |x|^y. */ - inexact = mpfr_underflow (z, rnd_mode == MPFR_RNDN ? MPFR_RNDZ - : rnd_mode, MPFR_SIGN_POS); - if (expo != NULL) - MPFR_SAVE_EXPO_UPDATE_FLAGS (*expo, MPFR_FLAGS_INEXACT - | MPFR_FLAGS_UNDERFLOW); - break; - } - - /* Real overflow? */ - if (MPFR_IS_INF (t)) - { - /* Note: we can probably use a low precision for this test. */ - mpfr_log (t, absx, MPFR_IS_NEG (y) ? MPFR_RNDU : MPFR_RNDD); - mpfr_mul (t, y, t, MPFR_RNDD); /* y * ln|x| */ - MPFR_BLOCK (flags2, mpfr_exp (t, t, MPFR_RNDD)); - /* t = lower bound on exp(y * ln|x|) */ - if (MPFR_OVERFLOW (flags2)) - { - /* We have computed a lower bound on |x|^y, and it - overflowed. Therefore we have a real overflow - on |x|^y. */ - inexact = mpfr_overflow (z, rnd_mode, MPFR_SIGN_POS); - if (expo != NULL) - MPFR_SAVE_EXPO_UPDATE_FLAGS (*expo, MPFR_FLAGS_INEXACT - | MPFR_FLAGS_OVERFLOW); - break; - } - } - - k_non_zero = 1; - Ntmin = sizeof(mpfr_exp_t) * CHAR_BIT; - if (Ntmin > Nt) - { - Nt = Ntmin; - mpfr_set_prec (t, Nt); - } - mpfr_init2 (u, Nt); - mpfr_init2 (k, Ntmin); - mpfr_log2 (k, absx, MPFR_RNDN); - mpfr_mul (k, y, k, MPFR_RNDN); - mpfr_round (k, k); - MPFR_LOG_VAR (k); - /* |y| < 2^Ntmin, therefore |k| < 2^Nt. */ - continue; - } - if (MPFR_LIKELY (MPFR_CAN_ROUND (t, Nt - err, Nz, rnd_mode))) - { - inexact = mpfr_set (z, t, rnd_mode); - break; - } - - /* check exact power, except when y is an integer (since the - exact cases for y integer have already been filtered out) */ - if (check_exact_case == 0 && ! y_is_integer) - { - if (mpfr_pow_is_exact (z, absx, y, rnd_mode, &inexact)) - break; - check_exact_case = 1; - } - - /* reactualisation of the precision */ - MPFR_ZIV_NEXT (ziv_loop, Nt); - mpfr_set_prec (t, Nt); - if (k_non_zero) - mpfr_set_prec (u, Nt); - } - MPFR_ZIV_FREE (ziv_loop); - - if (k_non_zero) - { - int inex2; - long lk; - - /* The rounded result in an unbounded exponent range is z * 2^k. As - * MPFR chooses underflow after rounding, the mpfr_mul_2si below will - * correctly detect underflows and overflows. However, in rounding to - * nearest, if z * 2^k = 2^(emin - 2), then the double rounding may - * affect the result. We need to cope with that before overwriting z. - * If inexact >= 0, then the real result is <= 2^(emin - 2), so that - * o(2^(emin - 2)) = +0 is correct. If inexact < 0, then the real - * result is > 2^(emin - 2) and we need to round to 2^(emin - 1). - */ - MPFR_ASSERTN (MPFR_EMAX_MAX <= LONG_MAX); - lk = mpfr_get_si (k, MPFR_RNDN); - if (rnd_mode == MPFR_RNDN && inexact < 0 && - MPFR_GET_EXP (z) + lk == __gmpfr_emin - 1 && mpfr_powerof2_raw (z)) - { - /* Rounding to nearest, real result > z * 2^k = 2^(emin - 2), - * underflow case: as the minimum precision is > 1, we will - * obtain the correct result and exceptions by replacing z by - * nextabove(z). - */ - MPFR_ASSERTN (MPFR_PREC_MIN > 1); - mpfr_nextabove (z); - } - mpfr_clear_flags (); - inex2 = mpfr_mul_2si (z, z, lk, rnd_mode); - if (inex2) /* underflow or overflow */ - { - inexact = inex2; - if (expo != NULL) - MPFR_SAVE_EXPO_UPDATE_FLAGS (*expo, __gmpfr_flags); - } - mpfr_clears (u, k, (mpfr_ptr) 0); - } - mpfr_clear (t); - - /* update the sign of the result if x was negative */ - if (MPFR_IS_NEG (x) && is_odd (y)) - { - MPFR_SET_NEG(z); - inexact = -inexact; - } - - return inexact; -} - -/* The computation of z = pow(x,y) is done by - z = exp(y * log(x)) = x^y - For the special cases, see Section F.9.4.4 of the C standard: - _ pow(±0, y) = ±inf for y an odd integer < 0. - _ pow(±0, y) = +inf for y < 0 and not an odd integer. - _ pow(±0, y) = ±0 for y an odd integer > 0. - _ pow(±0, y) = +0 for y > 0 and not an odd integer. - _ pow(-1, ±inf) = 1. - _ pow(+1, y) = 1 for any y, even a NaN. - _ pow(x, ±0) = 1 for any x, even a NaN. - _ pow(x, y) = NaN for finite x < 0 and finite non-integer y. - _ pow(x, -inf) = +inf for |x| < 1. - _ pow(x, -inf) = +0 for |x| > 1. - _ pow(x, +inf) = +0 for |x| < 1. - _ pow(x, +inf) = +inf for |x| > 1. - _ pow(-inf, y) = -0 for y an odd integer < 0. - _ pow(-inf, y) = +0 for y < 0 and not an odd integer. - _ pow(-inf, y) = -inf for y an odd integer > 0. - _ pow(-inf, y) = +inf for y > 0 and not an odd integer. - _ pow(+inf, y) = +0 for y < 0. - _ pow(+inf, y) = +inf for y > 0. */ -int -mpfr_pow (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, mpfr_rnd_t rnd_mode) -{ - int inexact; - int cmp_x_1; - int y_is_integer; - MPFR_SAVE_EXPO_DECL (expo); - - MPFR_LOG_FUNC (("x[%#R]=%R y[%#R]=%R rnd=%d", x, x, y, y, rnd_mode), - ("z[%#R]=%R inexact=%d", z, z, inexact)); - - if (MPFR_ARE_SINGULAR (x, y)) - { - /* pow(x, 0) returns 1 for any x, even a NaN. */ - if (MPFR_UNLIKELY (MPFR_IS_ZERO (y))) - return mpfr_set_ui (z, 1, rnd_mode); - else if (MPFR_IS_NAN (x)) - { - MPFR_SET_NAN (z); - MPFR_RET_NAN; - } - else if (MPFR_IS_NAN (y)) - { - /* pow(+1, NaN) returns 1. */ - if (mpfr_cmp_ui (x, 1) == 0) - return mpfr_set_ui (z, 1, rnd_mode); - MPFR_SET_NAN (z); - MPFR_RET_NAN; - } - else if (MPFR_IS_INF (y)) - { - if (MPFR_IS_INF (x)) - { - if (MPFR_IS_POS (y)) - MPFR_SET_INF (z); - else - MPFR_SET_ZERO (z); - MPFR_SET_POS (z); - MPFR_RET (0); - } - else - { - int cmp; - cmp = mpfr_cmpabs (x, __gmpfr_one) * MPFR_INT_SIGN (y); - MPFR_SET_POS (z); - if (cmp > 0) - { - /* Return +inf. */ - MPFR_SET_INF (z); - MPFR_RET (0); - } - else if (cmp < 0) - { - /* Return +0. */ - MPFR_SET_ZERO (z); - MPFR_RET (0); - } - else - { - /* Return 1. */ - return mpfr_set_ui (z, 1, rnd_mode); - } - } - } - else if (MPFR_IS_INF (x)) - { - int negative; - /* Determine the sign now, in case y and z are the same object */ - negative = MPFR_IS_NEG (x) && is_odd (y); - if (MPFR_IS_POS (y)) - MPFR_SET_INF (z); - else - MPFR_SET_ZERO (z); - if (negative) - MPFR_SET_NEG (z); - else - MPFR_SET_POS (z); - MPFR_RET (0); - } - else - { - int negative; - MPFR_ASSERTD (MPFR_IS_ZERO (x)); - /* Determine the sign now, in case y and z are the same object */ - negative = MPFR_IS_NEG(x) && is_odd (y); - if (MPFR_IS_NEG (y)) - MPFR_SET_INF (z); - else - MPFR_SET_ZERO (z); - if (negative) - MPFR_SET_NEG (z); - else - MPFR_SET_POS (z); - MPFR_RET (0); - } - } - - /* x^y for x < 0 and y not an integer is not defined */ - y_is_integer = mpfr_integer_p (y); - if (MPFR_IS_NEG (x) && ! y_is_integer) - { - MPFR_SET_NAN (z); - MPFR_RET_NAN; - } - - /* now the result cannot be NaN: - (1) either x > 0 - (2) or x < 0 and y is an integer */ - - cmp_x_1 = mpfr_cmpabs (x, __gmpfr_one); - if (cmp_x_1 == 0) - return mpfr_set_si (z, MPFR_IS_NEG (x) && is_odd (y) ? -1 : 1, rnd_mode); - - /* now we have: - (1) either x > 0 - (2) or x < 0 and y is an integer - and in addition |x| <> 1. - */ - - /* detect overflow: an overflow is possible if - (a) |x| > 1 and y > 0 - (b) |x| < 1 and y < 0. - FIXME: this assumes 1 is always representable. - - FIXME2: maybe we can test overflow and underflow simultaneously. - The idea is the following: first compute an approximation to - y * log2|x|, using rounding to nearest. If |x| is not too near from 1, - this approximation should be accurate enough, and in most cases enable - one to prove that there is no underflow nor overflow. - Otherwise, it should enable one to check only underflow or overflow, - instead of both cases as in the present case. - */ - if (cmp_x_1 * MPFR_SIGN (y) > 0) - { - mpfr_t t; - int negative, overflow; - - MPFR_SAVE_EXPO_MARK (expo); - mpfr_init2 (t, 53); - /* we want a lower bound on y*log2|x|: - (i) if x > 0, it suffices to round log2(x) toward zero, and - to round y*o(log2(x)) toward zero too; - (ii) if x < 0, we first compute t = o(-x), with rounding toward 1, - and then follow as in case (1). */ - if (MPFR_SIGN (x) > 0) - mpfr_log2 (t, x, MPFR_RNDZ); - else - { - mpfr_neg (t, x, (cmp_x_1 > 0) ? MPFR_RNDZ : MPFR_RNDU); - mpfr_log2 (t, t, MPFR_RNDZ); - } - mpfr_mul (t, t, y, MPFR_RNDZ); - overflow = mpfr_cmp_si (t, __gmpfr_emax) > 0; - mpfr_clear (t); - MPFR_SAVE_EXPO_FREE (expo); - if (overflow) - { - MPFR_LOG_MSG (("early overflow detection\n", 0)); - negative = MPFR_SIGN(x) < 0 && is_odd (y); - return mpfr_overflow (z, rnd_mode, negative ? -1 : 1); - } - } - - /* Basic underflow checking. One has: - * - if y > 0, |x^y| < 2^(EXP(x) * y); - * - if y < 0, |x^y| <= 2^((EXP(x) - 1) * y); - * so that one can compute a value ebound such that |x^y| < 2^ebound. - * If we have ebound <= emin - 2 (emin - 1 in directed rounding modes), - * then there is an underflow and we can decide the return value. - */ - if (MPFR_IS_NEG (y) ? (MPFR_GET_EXP (x) > 1) : (MPFR_GET_EXP (x) < 0)) - { - mpfr_t tmp; - mpfr_eexp_t ebound; - int inex2; - - /* We must restore the flags. */ - MPFR_SAVE_EXPO_MARK (expo); - mpfr_init2 (tmp, sizeof (mpfr_exp_t) * CHAR_BIT); - inex2 = mpfr_set_exp_t (tmp, MPFR_GET_EXP (x), MPFR_RNDN); - MPFR_ASSERTN (inex2 == 0); - if (MPFR_IS_NEG (y)) - { - inex2 = mpfr_sub_ui (tmp, tmp, 1, MPFR_RNDN); - MPFR_ASSERTN (inex2 == 0); - } - mpfr_mul (tmp, tmp, y, MPFR_RNDU); - if (MPFR_IS_NEG (y)) - mpfr_nextabove (tmp); - /* tmp doesn't necessarily fit in ebound, but that doesn't matter - since we get the minimum value in such a case. */ - ebound = mpfr_get_exp_t (tmp, MPFR_RNDU); - mpfr_clear (tmp); - MPFR_SAVE_EXPO_FREE (expo); - if (MPFR_UNLIKELY (ebound <= - __gmpfr_emin - (rnd_mode == MPFR_RNDN ? 2 : 1))) - { - /* warning: mpfr_underflow rounds away from 0 for MPFR_RNDN */ - MPFR_LOG_MSG (("early underflow detection\n", 0)); - return mpfr_underflow (z, - rnd_mode == MPFR_RNDN ? MPFR_RNDZ : rnd_mode, - MPFR_SIGN (x) < 0 && is_odd (y) ? -1 : 1); - } - } - - /* If y is an integer, we can use mpfr_pow_z (based on multiplications), - but if y is very large (I'm not sure about the best threshold -- VL), - we shouldn't use it, as it can be very slow and take a lot of memory - (and even crash or make other programs crash, as several hundred of - MBs may be necessary). Note that in such a case, either x = +/-2^b - (this case is handled below) or x^y cannot be represented exactly in - any precision supported by MPFR (the general case uses this property). - */ - if (y_is_integer && (MPFR_GET_EXP (y) <= 256)) - { - mpz_t zi; - - MPFR_LOG_MSG (("special code for y not too large integer\n", 0)); - mpz_init (zi); - mpfr_get_z (zi, y, MPFR_RNDN); - inexact = mpfr_pow_z (z, x, zi, rnd_mode); - mpz_clear (zi); - return inexact; - } - - /* Special case (+/-2^b)^Y which could be exact. If x is negative, then - necessarily y is a large integer. */ - { - mpfr_exp_t b = MPFR_GET_EXP (x) - 1; - - MPFR_ASSERTN (b >= LONG_MIN && b <= LONG_MAX); /* FIXME... */ - if (mpfr_cmp_si_2exp (x, MPFR_SIGN(x), b) == 0) - { - mpfr_t tmp; - int sgnx = MPFR_SIGN (x); - - MPFR_LOG_MSG (("special case (+/-2^b)^Y\n", 0)); - /* now x = +/-2^b, so x^y = (+/-1)^y*2^(b*y) is exact whenever b*y is - an integer */ - MPFR_SAVE_EXPO_MARK (expo); - mpfr_init2 (tmp, MPFR_PREC (y) + sizeof (long) * CHAR_BIT); - inexact = mpfr_mul_si (tmp, y, b, MPFR_RNDN); /* exact */ - MPFR_ASSERTN (inexact == 0); - /* Note: as the exponent range has been extended, an overflow is not - possible (due to basic overflow and underflow checking above, as - the result is ~ 2^tmp), and an underflow is not possible either - because b is an integer (thus either 0 or >= 1). */ - mpfr_clear_flags (); - inexact = mpfr_exp2 (z, tmp, rnd_mode); - mpfr_clear (tmp); - if (sgnx < 0 && is_odd (y)) - { - mpfr_neg (z, z, rnd_mode); - inexact = -inexact; - } - /* Without the following, the overflows3 test in tpow.c fails. */ - MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, __gmpfr_flags); - MPFR_SAVE_EXPO_FREE (expo); - return mpfr_check_range (z, inexact, rnd_mode); - } - } - - MPFR_SAVE_EXPO_MARK (expo); - - /* Case where |y * log(x)| is very small. Warning: x can be negative, in - that case y is a large integer. */ - { - mpfr_t t; - mpfr_exp_t err; - - /* We need an upper bound on the exponent of y * log(x). */ - mpfr_init2 (t, 16); - if (MPFR_IS_POS(x)) - mpfr_log (t, x, cmp_x_1 < 0 ? MPFR_RNDD : MPFR_RNDU); /* away from 0 */ - else - { - /* if x < -1, round to +Inf, else round to zero */ - mpfr_neg (t, x, (mpfr_cmp_si (x, -1) < 0) ? MPFR_RNDU : MPFR_RNDD); - mpfr_log (t, t, (mpfr_cmp_ui (t, 1) < 0) ? MPFR_RNDD : MPFR_RNDU); - } - MPFR_ASSERTN (MPFR_IS_PURE_FP (t)); - err = MPFR_GET_EXP (y) + MPFR_GET_EXP (t); - mpfr_clear (t); - mpfr_clear_flags (); - MPFR_SMALL_INPUT_AFTER_SAVE_EXPO (z, __gmpfr_one, - err, 0, - (MPFR_SIGN (y) > 0) ^ (cmp_x_1 < 0), - rnd_mode, expo, {}); - } - - /* General case */ - inexact = mpfr_pow_general (z, x, y, rnd_mode, y_is_integer, &expo); - - MPFR_SAVE_EXPO_FREE (expo); - return mpfr_check_range (z, inexact, rnd_mode); -} |