diff options
author | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2002-01-30 14:57:24 +0000 |
---|---|---|
committer | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2002-01-30 14:57:24 +0000 |
commit | 3da9c3b4b41b6b855442b285e592009544e15d2c (patch) | |
tree | 959cc54a282f5f6118bfd5077911f3faeb1e96b6 /set_z.c | |
parent | 623ff615987dc4d5917f4f8fdb5676adf6575e11 (diff) | |
download | mpfr-3da9c3b4b41b6b855442b285e592009544e15d2c.tar.gz |
mpfr_set_z rewritten.
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@1675 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'set_z.c')
-rw-r--r-- | set_z.c | 109 |
1 files changed, 57 insertions, 52 deletions
@@ -1,6 +1,6 @@ /* mpfr_set_z -- set a floating-point number from a multiple-precision integer -Copyright (C) 1999, 2001 Free Software Foundation, Inc. +Copyright (C) 1999-2002 Free Software Foundation, Inc. This file is part of the MPFR Library. @@ -29,7 +29,7 @@ MA 02111-1307, USA. */ int mpfr_set_z (mpfr_ptr f, mpz_srcptr z, mp_rnd_t rnd_mode) { - mp_size_t fn, zn, dif, sh; + mp_size_t fn, zn, dif; int k, sign_z, inex; mp_limb_t *fp, *zp; mp_exp_t exp; @@ -58,7 +58,6 @@ mpfr_set_z (mpfr_ptr f, mpz_srcptr z, mp_rnd_t rnd_mode) return mpfr_set_overflow(f, rnd_mode, sign_z); if (exp + 1 < __mpfr_emin) return mpfr_set_underflow(f, rnd_mode, sign_z); - MPFR_EXP(f) = exp; if (MPFR_SIGN(f) * sign_z < 0) MPFR_CHANGE_SIGN(f); @@ -66,9 +65,10 @@ mpfr_set_z (mpfr_ptr f, mpz_srcptr z, mp_rnd_t rnd_mode) if (dif >= 0) { mp_limb_t cc; + int sh; /* number has to be truncated */ - if (k) + if (k != 0) { mpn_lshift(fp, zp + dif, fn, k); if (dif != 0) @@ -85,67 +85,73 @@ mpfr_set_z (mpfr_ptr f, mpz_srcptr z, mp_rnd_t rnd_mode) (rnd_mode == GMP_RNDD && sign_z > 0)) rnd_mode = GMP_RNDZ; + /* remaining bits... */ if (rnd_mode == GMP_RNDN) { - mp_limb_t c2; - - if (sh) - c2 = MP_LIMB_T_ONE << (sh - 1); - else /* sh = 0 */ - { - c2 = MP_LIMB_T_HIGHBIT; - cc = --dif >= 0 ? zp[dif] << k : 0; - if (dif > 0 && k) - cc += zp[dif-1] >> (BITS_PER_MP_LIMB - k); - } - /* now compares cc to c2 */ - if (cc > c2) + /* 1) If rounding bit is 0, behave like rounding to 0. + 2) Determine the sticky bit (cc != 0). */ + if (sh != 0) { - mpfr_add_one_ulp(f, rnd_mode); - inex = sign_z; + mp_limb_t rb; + + rb = MP_LIMB_T_ONE << (sh - 1); + if ((cc & rb) == 0) + rnd_mode = GMP_RNDZ; /* rounding bit is 0 */ + else + cc &= ~rb; + if (cc == 0 && dif > 0) + cc = zp[--dif] << k; } - else if (cc < c2) + else /* sh == 0 */ { - inex = -sign_z; + MPFR_ASSERTN(cc == 0); + if (dif > 0) + cc = zp[--dif] << k; + if ((cc & MP_LIMB_T_HIGHBIT) == 0) + rnd_mode = GMP_RNDZ; /* rounding bit is 0 */ + else + cc <<= 1; } - else + + while (cc == 0 && dif > 0) + cc = zp[--dif]; + + if (rnd_mode == GMP_RNDN && cc == 0) /* even rounding */ { - cc = 0; - while (cc == 0 && dif > 0) - cc = zp[--dif]; - if (cc != 0 || (fp[0] & (MP_LIMB_T_ONE << sh))) - { - mpfr_add_one_ulp(f, rnd_mode); - inex = sign_z; - } - else - inex = -sign_z; + cc = 1; + if ((fp[0] & (MP_LIMB_T_ONE << sh)) == 0) + rnd_mode = GMP_RNDZ; } + } /* rnd_mode == GMP_RNDN */ + else if (cc == 0 && dif > 0) + { + cc = zp[--dif] << k; + while (cc == 0 && dif > 0) + cc = zp[--dif]; } + + if (cc == 0) + inex = 0; + else if (rnd_mode == GMP_RNDZ) + inex = -sign_z; else { - /* remaining bits... */ - if (cc == 0) - { - if (dif > 0) - cc = zp[--dif] << k; - while (cc == 0 && dif > 0) - cc = zp[--dif]; - } - if (cc == 0) - inex = 0; - else if (rnd_mode == GMP_RNDZ) - inex = -sign_z; - else + if (mpn_add_1(fp, fp, fn, MP_LIMB_T_ONE << sh)) { - mpfr_add_one_ulp(f, rnd_mode); - inex = sign_z; + if (exp == __mpfr_emax) + return mpfr_set_overflow(f, rnd_mode, sign_z); + else + { + exp++; + fp[fn-1] = MP_LIMB_T_HIGHBIT; + } } + inex = sign_z; } - } - else + } /* dif >= 0 */ + else /* dif < 0 */ { - if (k) + if (k != 0) mpn_lshift(fp - dif, zp, zn, k); else MPN_COPY(fp - dif, zp, zn); @@ -154,9 +160,8 @@ mpfr_set_z (mpfr_ptr f, mpz_srcptr z, mp_rnd_t rnd_mode) inex = 0; /* result is exact */ } - if (exp > __mpfr_emax) - return mpfr_set_overflow(f, rnd_mode, sign_z); if (exp < __mpfr_emin) return mpfr_set_underflow(f, rnd_mode, sign_z); + MPFR_EXP(f) = exp; MPFR_RET(inex); } |