summaryrefslogtreecommitdiff
path: root/hypot.c
diff options
context:
space:
mode:
authorvlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2005-11-02 17:22:13 +0000
committervlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2005-11-02 17:22:13 +0000
commit965d51f78cc3fdf9c5f8d6f8286a9b7e53bd2deb (patch)
tree89d3582f9c65a65616638ab5672256e722b8f6d1 /hypot.c
parent041b6b2d9b0f969e1af7abf853f1acdd458b45fc (diff)
downloadmpfr-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.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/hypot.c b/hypot.c
index 3075c229b..9efd63110 100644
--- a/hypot.c
+++ b/hypot.c
@@ -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 */