summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Enge <andreas.enge@inria.fr>2010-04-11 17:37:02 +0000
committerAndreas Enge <andreas.enge@inria.fr>2010-04-11 17:37:02 +0000
commit26441d95a4cf4c6fa5aa9e5233f0867de074104a (patch)
tree2390d3b0af51412c7725e966cb532f433b90d2b6
parent915253d3386794e5dbfb388a69a732c8e4fc5bfc (diff)
downloadmpc-git-26441d95a4cf4c6fa5aa9e5233f0867de074104a.tar.gz
pow_ui.c: added code for a second binary trial in certain cases
pow_ui.dat: example needing a second pass git-svn-id: svn+ssh://scm.gforge.inria.fr/svnroot/mpc/trunk@756 211d60ee-9f03-0410-a15a-8952a2c7a4e4
-rw-r--r--src/pow_ui.c110
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/pow_ui.dat2
3 files changed, 69 insertions, 47 deletions
diff --git a/src/pow_ui.c b/src/pow_ui.c
index 4337294..c1a3cb1 100644
--- a/src/pow_ui.c
+++ b/src/pow_ui.c
@@ -27,7 +27,6 @@ mpc_pow_ui_naive (mpc_ptr z, mpc_srcptr x, unsigned long y, mpc_rnd_t rnd)
{
int inex;
mpc_t t;
-
mpc_init3 (t, sizeof (unsigned long) * CHAR_BIT, MPFR_PREC_MIN);
mpc_set_ui (t, y, MPC_RNDNN); /* exact */
inex = mpc_pow (z, x, t, rnd);
@@ -42,10 +41,10 @@ mpc_pow_ui (mpc_ptr z, mpc_srcptr x, unsigned long y, mpc_rnd_t rnd)
{
int inex;
mpc_t t, x3;
- mp_prec_t p, er, ei;
+ mp_prec_t p;
unsigned long l, l0, u;
- mp_exp_t diff;
int has3; /* non-zero if y has '11' in its binary representation */
+ int loop, done;
if (!mpc_fin_p (x) || mpfr_zero_p (MPC_RE (x)) || mpfr_zero_p (MPC_IM(x))
|| y == 0)
@@ -76,55 +75,76 @@ mpc_pow_ui (mpc_ptr z, mpc_srcptr x, unsigned long y, mpc_rnd_t rnd)
if (has3)
mpc_init2 (x3, p);
- mpc_sqr (t, x, MPC_RNDNN);
- if (has3) {
- mpc_mul (x3, t, x, MPC_RNDNN);
- if ((y >> l) & 1) /* y starts with 11... */
- mpc_set (t, x3, MPC_RNDNN);
- }
- while (l-- > 0) {
- mpc_sqr (t, t, MPC_RNDNN);
- if ((y >> l) & 1) {
- if ((l > 0) && ((y >> (l-1)) & 1)) /* implies has3 <> 0 */ {
- l --;
- mpc_sqr (t, t, MPC_RNDNN);
- mpc_mul (t, t, x3, MPC_RNDNN);
+ loop = 0;
+ done = 0;
+ while (!done) {
+ loop++;
+
+ mpc_sqr (t, x, MPC_RNDNN);
+ if (has3) {
+ mpc_mul (x3, t, x, MPC_RNDNN);
+ if ((y >> l) & 1) /* y starts with 11... */
+ mpc_set (t, x3, MPC_RNDNN);
+ }
+ while (l-- > 0) {
+ mpc_sqr (t, t, MPC_RNDNN);
+ if ((y >> l) & 1) {
+ if ((l > 0) && ((y >> (l-1)) & 1)) /* implies has3 <> 0 */ {
+ l--;
+ mpc_sqr (t, t, MPC_RNDNN);
+ mpc_mul (t, t, x3, MPC_RNDNN);
+ }
+ else
+ mpc_mul (t, t, x, MPC_RNDNN);
}
- else
- mpc_mul (t, t, x, MPC_RNDNN);
}
- }
- if (has3)
- mpc_clear (x3);
- /* the absolute error on the real and imaginary parts is bounded
- by |x|^y (|1+2^{-p}|^{y-1}-1) [see algorithms.tex].
- For em <= 1, (1+e)^m - 1 <= 2em since
- (1+e)^m - 1 = exp(m*log(1+e))-1 <= exp(em)-1 <= 2em for em <= 1.
- We apply this for e=2^{-p} and m=y-1, thus the absolute error is
- bounded by |x|^y 2^{1-p} (y-1) < 2^{l0+1-p} */
- if (mpfr_zero_p (MPC_RE(t)) || mpfr_zero_p (MPC_IM(t)))
- inex = mpc_pow_ui_naive (z, x, y, rnd);
- /* since mpfr_get_exp() is not defined for zero */
- else {
- diff = mpfr_get_exp (MPC_RE(t)) - mpfr_get_exp (MPC_IM(t));
- /* the factor on the real part is 2+2^(-diff+2) <= 4 for diff >= 1
- and <= 2^(-diff+3) for diff <= 0 */
- er = (diff >= 1) ? l0 + 3 : l0 + (-diff) + 4;
- /* the factor on the imaginary part is 2+2^(diff+2) <= 4 for diff <= -1
- and <= 2^(diff+3) for diff >= 0 */
- ei = (diff <= -1) ? l0 + 3 : l0 + diff + 4;
- if (mpfr_can_round (MPC_RE(t), p - er, GMP_RNDZ, GMP_RNDZ,
- MPFR_PREC(MPC_RE(z)) + (MPC_RND_RE(rnd) == GMP_RNDN))
- && mpfr_can_round (MPC_IM(t), p - ei, GMP_RNDZ, GMP_RNDZ,
- MPFR_PREC(MPC_IM(z)) + (MPC_RND_IM(rnd) == GMP_RNDN)))
- inex = mpc_set (z, t, rnd);
- else
+ /* the absolute error on the real and imaginary parts is bounded
+ by |x|^y (|1+2^{-p}|^{y-1}-1) [see algorithms.tex].
+ For em <= 1, (1+e)^m - 1 <= 2em since
+ (1+e)^m - 1 = exp(m*log(1+e))-1 <= exp(em)-1 <= 2em for em <= 1.
+ We apply this for e=2^{-p} and m=y-1, thus the absolute error is
+ bounded by |x|^y 2^{1-p} (y-1) < 2^{l0+1-p} */
+ if (mpfr_zero_p (MPC_RE(t)) || mpfr_zero_p (MPC_IM(t))) {
inex = mpc_pow_ui_naive (z, x, y, rnd);
+ /* since mpfr_get_exp() is not defined for zero */
+ done = 1;
+ }
+ else {
+ mp_exp_t diff;
+ mp_prec_t er, ei;
+ diff = mpfr_get_exp (MPC_RE(t)) - mpfr_get_exp (MPC_IM(t));
+ /* the factor on the real part is 2+2^(-diff+2) <= 4 for diff >= 1
+ and <= 2^(-diff+3) for diff <= 0 */
+ er = (diff >= 1) ? l0 + 3 : l0 + (-diff) + 4;
+ /* the factor on the imaginary part is 2+2^(diff+2) <= 4 for diff <= -1
+ and <= 2^(diff+3) for diff >= 0 */
+ ei = (diff <= -1) ? l0 + 3 : l0 + diff + 4;
+ if (mpfr_can_round (MPC_RE(t), p - er, GMP_RNDZ, GMP_RNDZ,
+ MPFR_PREC(MPC_RE(z)) + (MPC_RND_RE(rnd) == GMP_RNDN))
+ && mpfr_can_round (MPC_IM(t), p - ei, GMP_RNDZ, GMP_RNDZ,
+ MPFR_PREC(MPC_IM(z)) + (MPC_RND_IM(rnd) == GMP_RNDN))) {
+ inex = mpc_set (z, t, rnd);
+ done = 1;
+ }
+ else if (loop == 1 && SAFE_ABS(mp_prec_t, diff) < MPC_MAX_PREC(x)) {
+ /* common case, make a second trial at higher precision */
+ p += MPC_MAX_PREC(x);
+ mpc_set_prec (t, p);
+ if (has3)
+ mpc_set_prec (x3, p);
+ l = l0 - 2;
+ }
+ else {
+ inex = mpc_pow_ui_naive (z, x, y, rnd);
+ done = 1;
+ }
+ }
}
mpc_clear (t);
+ if (has3)
+ mpc_clear (x3);
return inex;
}
-
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 29f81a5..6907381 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -4,10 +4,10 @@ AM_CPPFLAGS = -I$(top_srcdir)/src
LDADD = libmpc-tests.la $(top_builddir)/src/libmpc.la
LOADLIBES=$(DEFS) -I$(top_srcdir)/src $(CPPFLAGS) $(CFLAGS) $(top_builddir)/src/.libs/libmpc.a $(LIBS)
-check_PROGRAMS = tpow_ui tabs tacos tacosh tadd tadd_fr tadd_ui targ tasin tasinh \
+check_PROGRAMS = tabs tacos tacosh tadd tadd_fr tadd_ui targ tasin tasinh \
tatan tatanh tconj tcos tcosh tdiv tdiv_2exp tdiv_fr tdiv_ui texp tfr_div \
tfr_sub timag tio_str tlog tmul tmul_2exp tmul_fr tmul_i tmul_si \
-tmul_ui tneg tnorm tpow tpow_ld tpow_d tpow_fr tpow_si tpow_z tprec \
+tmul_ui tneg tnorm tpow tpow_ld tpow_d tpow_fr tpow_si tpow_ui tpow_z tprec \
tproj treal treimref tset tsin tsinh tsqr tsqrt tstrtoc tsub tsub_fr tsub_ui \
ttan ttanh tui_div tui_ui_sub tget_version
diff --git a/tests/pow_ui.dat b/tests/pow_ui.dat
index be8c369..744bd32 100644
--- a/tests/pow_ui.dat
+++ b/tests/pow_ui.dat
@@ -91,3 +91,5 @@
? ? 53 +inf 53 +inf 53 1e100000000 53 1e100000000 1000000000 N N
# underflow
? ? 53 0 53 0 53 1e-100000000 53 1e-100000000 1000000000 N N
+# cannot round after one loop
+? ? 420 -0x1.c3fb41a71665f9a144927e70cbc2dc899e9e30880c0b5aa924ad8a538b4cd06e503f38bdbb7cfcfded29f7504fe0c91ecd4230984@-187 420 -0xc.82a09ac98133eb05b2643c98eb1c8e1a1609e75f682b14098176abd6c8b4b3c6c72dadaf8929f9bd87f8c78d03361bacb9fb13140@-292 420 0x1.cf13ce58adc4e639fd1c3063ffc9291433647999951bc04ba6797ec4de0335336ad0a28df18573d3b6322ebab662c08eadaed4a8e@-8 420 0x3.cf71d602ca6f754ebd6af522154f3ee1c46da0a52deb1f60016fca4b1e0b4b447b752169e837bb1866aa3734850cd158a7e3ca33c@-9 24 N N