diff options
author | pelissip <pelissip@280ebfd0-de03-0410-8827-d642c229c3f4> | 2004-02-16 17:35:26 +0000 |
---|---|---|
committer | pelissip <pelissip@280ebfd0-de03-0410-8827-d642c229c3f4> | 2004-02-16 17:35:26 +0000 |
commit | d1017f08eafd969e9ebdf2ead3e24d1a0eae5753 (patch) | |
tree | cc4d7e8429e81bc8651c330f994626fd8667f5f0 /gmp_op.c | |
parent | 5094d98158eff8a199b86a34bc1a00a8308fbfe9 (diff) | |
download | mpfr-d1017f08eafd969e9ebdf2ead3e24d1a0eae5753.tar.gz |
Fix bug of add_q and sub_q with special values (NAN, INF and ZERO).
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@2735 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'gmp_op.c')
-rw-r--r-- | gmp_op.c | 57 |
1 files changed, 53 insertions, 4 deletions
@@ -108,10 +108,32 @@ mpfr_add_q (mpfr_ptr y, mpfr_srcptr x, mpq_srcptr z, mp_rnd_t rnd_mode) mpfr_t t,q; mp_prec_t p = MPFR_PREC(y)+10; int res; + + if (MPFR_UNLIKELY(MPFR_IS_SINGULAR(x))) + { + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(y); + MPFR_RET_NAN; + } + else if (MPFR_IS_INF(x)) + { + MPFR_SET_INF (y); + MPFR_SET_SAME_SIGN (y, x); + MPFR_RET (0); + } + else + { + MPFR_ASSERTD( MPFR_IS_ZERO(x)); + return mpfr_set_q (y, z, rnd_mode); + } + } + mpfr_inits2(p, t, q, NULL); do { - mpfr_set_q(q, z, GMP_RNDN); /* Error <= 1/2ulp */ - mpfr_add(t, x, q, GMP_RNDN); /* Error <= 1 ulp */ + mpfr_set_q(q, z, GMP_RNDN); /* Error <= 1/2 ulp(q) */ + mpfr_add(t, x, q, GMP_RNDN); /* Error <= 1/2 ulp(t) */ + /* Error / ulp(t) <= 1/2 + 1/2 * 2^(EXP(q)-EXP(t)) */ res = mpfr_can_round(t, p-1, GMP_RNDN, GMP_RNDZ, MPFR_PREC(y) + (rnd_mode == GMP_RNDN) ); if (!res) @@ -132,10 +154,37 @@ mpfr_sub_q (mpfr_ptr y, mpfr_srcptr x, mpq_srcptr z,mp_rnd_t rnd_mode) mpfr_t t,q; mp_prec_t p = MPFR_PREC(y)+10; int res; + + if (MPFR_UNLIKELY(MPFR_IS_SINGULAR(x))) + { + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN (y); + MPFR_RET_NAN; + } + else if (MPFR_IS_INF(x)) + { + MPFR_SET_INF (y); + MPFR_SET_SAME_SIGN (y, x); + MPFR_RET (0); + } + else + { + MPFR_ASSERTD( MPFR_IS_ZERO(x)); + if (rnd_mode == GMP_RNDU) + rnd_mode = GMP_RNDD; + else if (rnd_mode == GMP_RNDD) + rnd_mode = GMP_RNDU; + res = mpfr_set_q (y, z, rnd_mode); + MPFR_CHANGE_SIGN (y); + return -res; + } + } + mpfr_inits2(p, t, q, NULL); do { - mpfr_set_q(q, z, GMP_RNDN); /* Error <= 1/2ulp */ - mpfr_sub(t, x, q, GMP_RNDN); /* Error <= 1 ulp */ + mpfr_set_q(q, z, GMP_RNDN); /* Error <= 1/2 ulp(q) */ + mpfr_sub(t, x, q, GMP_RNDN); /* Error <= 1/2 ulp(t) */ res = mpfr_can_round(t, p-1, GMP_RNDN, GMP_RNDZ, MPFR_PREC(y) + (rnd_mode == GMP_RNDN) ); if (!res) |