diff options
author | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2005-11-02 17:22:13 +0000 |
---|---|---|
committer | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2005-11-02 17:22:13 +0000 |
commit | 965d51f78cc3fdf9c5f8d6f8286a9b7e53bd2deb (patch) | |
tree | 89d3582f9c65a65616638ab5672256e722b8f6d1 /hypot.c | |
parent | 041b6b2d9b0f969e1af7abf853f1acdd458b45fc (diff) | |
download | mpfr-965d51f78cc3fdf9c5f8d6f8286a9b7e53bd2deb.tar.gz |
Merged the changes from branch vlefevre:
* mpfr-impl.h: Added MPFR_RNDRAW_GEN based on MPFR_RNDRAW and
MPFR_RNDRAW_EVEN codes, but taking an additional argument: a
handler executed in rounding to nearest mode when the value
is the middle of two consecutive numbers in dest precision.
MPFR_RNDRAW and MPFR_RNDRAW_EVEN are now defined by a "call"
to MPFR_RNDRAW_GEN.
* cache.c: Clean-up and use MPFR_RNDRAW_GEN instead of
MPFR_RNDRAW_EVEN to avoid an unnecessary correction in the
halfway case.
* hypot.c: Fixed mpfr_hypot when the rounding mode is to nearest,
x is "much larger" than y, and x is the middle of two consecutive
numbers in the target precision.
* tests/thypot.c: Added the corresponding testcase.
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@3929 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'hypot.c')
-rw-r--r-- | hypot.c | 24 |
1 files changed, 19 insertions, 5 deletions
@@ -73,6 +73,7 @@ mpfr_hypot (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, mp_rnd_t rnd_mode) Ey = MPFR_GET_EXP (y); diff_exp = (mp_exp_unsigned_t) Ex - Ey; + Nx = MPFR_PREC (x); /* Precision of input variable */ Nz = MPFR_PREC (z); /* Precision of output variable */ /* we have x < 2^Ex thus x^2 < 2^(2*Ex), @@ -87,10 +88,10 @@ mpfr_hypot (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, mp_rnd_t rnd_mode) if 2*diff_exp > Nx (see above as if Nz = Nx), therefore on Nz bits. Hence the condition: 2*diff_exp > MAX(Nz,Nx). */ - if (diff_exp > MAX (Nz, MPFR_PREC (x)) / 2) + if (diff_exp > MAX (Nz, Nx) / 2) /* result is |x| or |x|+ulp(|x|,Nz) */ { - if (rnd_mode == GMP_RNDU) + if (MPFR_UNLIKELY (rnd_mode == GMP_RNDU)) { /* If z > abs(x), then it was already rounded up; otherwise z = abs(x), and we need to add one ulp due to y. */ @@ -100,14 +101,27 @@ mpfr_hypot (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, mp_rnd_t rnd_mode) } else /* GMP_RNDZ, GMP_RNDD, GMP_RNDN */ { - inexact = mpfr_abs (z, x, rnd_mode); - return (inexact) ? inexact : -1; + if (MPFR_LIKELY (Nz >= Nx)) + { + mpfr_abs (z, x, rnd_mode); /* exact */ + return -1; + } + else + { + MPFR_SET_EXP (z, Ex); + MPFR_SET_SIGN (z, 1); + MPFR_RNDRAW_GEN (inexact, z, MPFR_MANT (x), Nx, rnd_mode, 1, + goto addoneulp, + if (MPFR_UNLIKELY (++MPFR_EXP (z) > __gmpfr_emax)) + return mpfr_overflow (z, rnd_mode, 1); + ); + return inexact ? inexact : -1; + } } } /* General case */ - Nx = MPFR_PREC(x); /* Precision of input variable */ Ny = MPFR_PREC(y); /* Precision of input variable */ /* compute the working precision -- see algorithms.ps */ |