diff options
author | zimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4> | 1999-06-14 07:42:12 +0000 |
---|---|---|
committer | zimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4> | 1999-06-14 07:42:12 +0000 |
commit | 34d6f9588b4db5a503749eb60fa88ed9afcf89b5 (patch) | |
tree | aaa292738483a635e75449d9e52c499ad13b84ab /set_z.c | |
parent | 2a473695f5fbf84be9f74703c041c12cf84dc98f (diff) | |
download | mpfr-34d6f9588b4db5a503749eb60fa88ed9afcf89b5.tar.gz |
set a mpfr from an integer
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@27 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'set_z.c')
-rw-r--r-- | set_z.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/set_z.c b/set_z.c new file mode 100644 index 000000000..cf6ee0899 --- /dev/null +++ b/set_z.c @@ -0,0 +1,74 @@ +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +/* set f to the integer z */ +int mpfr_set_z (f, z, rnd) mpfr_ptr f; mpz_srcptr z; +unsigned char rnd; +{ + int fn, zn, k, dif, sign_z, sh; mp_limb_t *fp = MANT(f), cc, c2; + + sign_z = mpz_cmp_ui(z,0); + if (sign_z==0) return (SIZE(f)=0); + fn = 1 + (PREC(f)-1)/mp_bits_per_limb; + zn = SIZ(z); + dif = zn-fn; + count_leading_zeros(k, PTR(z)[zn-1]); + EXP(f) = zn*mp_bits_per_limb-k; + if (SIGN(f)*sign_z<0) CHANGE_SIGN(f); + if (dif>=0) { /* number has to be truncated */ + if (k) { + mpn_lshift(fp, PTR(z) + dif, fn, k); + if (dif) *fp += PTR(z)[dif-1] >> (mp_bits_per_limb-k); + } + else MPN_COPY(fp, PTR(z) + dif, fn); + sh = fn*mp_bits_per_limb-PREC(f); + cc = *fp & (((mp_limb_t)1 << sh) - 1); + *fp = *fp & ~cc; + if (rnd==GMP_RNDN) { + if (sh) c2 = (mp_limb_t)1 << (sh-1); + else { /* sh=0 */ + c2 = (mp_limb_t)1 << (mp_bits_per_limb-1); + dif--; + cc = (dif>=0) ? PTR(z)[dif] : 0; + } + /* now compares cc to c2 */ + if (cc>c2) { mpfr_add_one_ulp(f); return cc; } + else if (cc<c2) goto towards_zero; + else { + cc=0; + while (dif>0 && (cc=PTR(z)[dif-1])==0) dif--; + if (cc) { mpfr_add_one_ulp(f); return cc; } + else /* exactly in middle: inexact in both cases */ + if (*fp & ((mp_limb_t)1<<sh)) { mpfr_add_one_ulp(f); return 1; } + else return 1; + } + } + else if ((sign_z>0 && rnd==GMP_RNDU) || (sign_z<0 && rnd==GMP_RNDD)) { + /* round towards infinity */ + /* result is exact iff all remaining bits are zero */ + if (dif>0 && cc==0) cc=PTR(z)[--dif]<<k; + while (cc==0 && dif>0) cc=PTR(z)[--dif]; + if (cc) { mpfr_add_one_ulp(f); return 1; } + else return 0; + } + else { /* round towards zero */ + /* result is exact iff all remaining bits are zero */ + towards_zero: + if (cc==0 && dif>0) cc=PTR(z)[--dif]<<k; + while (cc==0 && dif>0) cc=PTR(z)[--dif]; + return cc; + } + } + else { + if (k) mpn_lshift(fp-dif, PTR(z), zn, k); + else MPN_COPY(fp-dif, PTR(z), zn); + /* fill with zeroes */ + MPN_ZERO(fp, -dif); + return 0; /* result is exact */ + } +} + + + |