diff options
author | Kevin Ryde <user42@zip.com.au> | 2001-02-01 23:29:23 +0100 |
---|---|---|
committer | Kevin Ryde <user42@zip.com.au> | 2001-02-01 23:29:23 +0100 |
commit | 618be102b4c29f1e02e4a7d2244ae57b4bb544c9 (patch) | |
tree | 23f14ffeb18a23ed1c61258a65130fd2321bec75 /mpfr | |
parent | eca14f894e34ab2d288357712157d6f942ced7fa (diff) | |
download | gmp-618be102b4c29f1e02e4a7d2244ae57b4bb544c9.tar.gz |
* mpfr/*: Update to mpfr 2001.
Tweaks applied to mpfr-impl.h for __gmp_allocate_func renaming, and to trunc.c
for OPERATION_$* scheme.
Diffstat (limited to 'mpfr')
-rw-r--r-- | mpfr/add.c | 373 | ||||
-rw-r--r-- | mpfr/add_ui.c | 54 | ||||
-rw-r--r-- | mpfr/add_ulp.c | 34 | ||||
-rw-r--r-- | mpfr/agm.c | 110 | ||||
-rw-r--r-- | mpfr/clear.c | 6 | ||||
-rw-r--r-- | mpfr/cmp.c | 115 | ||||
-rw-r--r-- | mpfr/cmp_ui.c | 54 | ||||
-rw-r--r-- | mpfr/cputime.h | 25 | ||||
-rw-r--r-- | mpfr/div.c | 185 | ||||
-rw-r--r-- | mpfr/div_2exp.c | 15 | ||||
-rw-r--r-- | mpfr/div_ui.c | 73 | ||||
-rw-r--r-- | mpfr/dump.c | 63 | ||||
-rw-r--r-- | mpfr/eq.c | 135 | ||||
-rw-r--r-- | mpfr/exp.c | 166 | ||||
-rw-r--r-- | mpfr/exp2.c | 431 | ||||
-rw-r--r-- | mpfr/exp3.c | 250 | ||||
-rw-r--r-- | mpfr/extract.c | 66 | ||||
-rw-r--r-- | mpfr/generic.c | 230 | ||||
-rw-r--r-- | mpfr/get_str.c | 166 | ||||
-rw-r--r-- | mpfr/init.c | 39 | ||||
-rw-r--r-- | mpfr/inp_str.c | 105 | ||||
-rw-r--r-- | mpfr/log.c | 95 | ||||
-rw-r--r-- | mpfr/log2.c | 184 | ||||
-rw-r--r-- | mpfr/mpf2mpfr.h | 144 | ||||
-rw-r--r-- | mpfr/mpfr-impl.h | 123 | ||||
-rw-r--r-- | mpfr/mpfr-test.h | 82 | ||||
-rw-r--r-- | mpfr/mpfr.h | 234 | ||||
-rw-r--r-- | mpfr/mpz_set_fr.c | 63 | ||||
-rw-r--r-- | mpfr/mul.c | 67 | ||||
-rw-r--r-- | mpfr/mul_2exp.c | 11 | ||||
-rw-r--r-- | mpfr/mul_ui.c | 92 | ||||
-rw-r--r-- | mpfr/neg.c | 18 | ||||
-rw-r--r-- | mpfr/out_str.c | 27 | ||||
-rw-r--r-- | mpfr/pi.c | 220 | ||||
-rw-r--r-- | mpfr/pow.c | 96 | ||||
-rw-r--r-- | mpfr/print_raw.c | 47 | ||||
-rw-r--r-- | mpfr/print_rnd_mode.c | 10 | ||||
-rw-r--r-- | mpfr/random.c | 56 | ||||
-rw-r--r-- | mpfr/random2.c | 69 | ||||
-rw-r--r-- | mpfr/reldiff.c | 76 | ||||
-rw-r--r-- | mpfr/rnd_mode.c | 32 | ||||
-rw-r--r-- | mpfr/round.c | 160 | ||||
-rw-r--r-- | mpfr/set.c | 30 | ||||
-rw-r--r-- | mpfr/set_d.c | 88 | ||||
-rw-r--r-- | mpfr/set_dfl_prec.c | 9 | ||||
-rw-r--r-- | mpfr/set_f.c | 24 | ||||
-rw-r--r-- | mpfr/set_prc_raw.c | 49 | ||||
-rw-r--r-- | mpfr/set_prec.c | 33 | ||||
-rw-r--r-- | mpfr/set_q.c | 64 | ||||
-rw-r--r-- | mpfr/set_rnd.c | 38 | ||||
-rw-r--r-- | mpfr/set_si.c | 75 | ||||
-rw-r--r-- | mpfr/set_str.c | 155 | ||||
-rw-r--r-- | mpfr/set_str_raw.c | 48 | ||||
-rw-r--r-- | mpfr/set_z.c | 34 | ||||
-rw-r--r-- | mpfr/sin_cos.c | 246 | ||||
-rw-r--r-- | mpfr/sqrt.c | 117 | ||||
-rw-r--r-- | mpfr/sqrt_ui.c | 58 | ||||
-rw-r--r-- | mpfr/sqrtrem.c | 225 | ||||
-rw-r--r-- | mpfr/sub.c | 433 | ||||
-rw-r--r-- | mpfr/sub_ui.c | 54 | ||||
-rw-r--r-- | mpfr/swap.c | 59 | ||||
-rw-r--r-- | mpfr/trunc.c | 185 | ||||
-rw-r--r-- | mpfr/ui_div.c | 74 | ||||
-rw-r--r-- | mpfr/ui_sub.c | 68 | ||||
-rw-r--r-- | mpfr/urandomb.c | 78 |
65 files changed, 5431 insertions, 1414 deletions
diff --git a/mpfr/add.c b/mpfr/add.c index c9bebe443..63cbb9109 100644 --- a/mpfr/add.c +++ b/mpfr/add.c @@ -1,6 +1,6 @@ /* mpfr_add -- add two floating-point numbers -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -23,9 +23,13 @@ MA 02111-1307, USA. */ #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" + +/* #define DEBUG */ extern void mpfr_sub1 _PROTO((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, - unsigned char, int)); + mp_rnd_t, int)); +void mpfr_add1 (mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t, int); #define ONE ((mp_limb_t) 1) @@ -35,14 +39,14 @@ extern void mpfr_sub1 _PROTO((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, void #if __STDC__ -mpfr_add1(mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, - unsigned char rnd_mode, int diff_exp) +mpfr_add1 (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, + mp_rnd_t rnd_mode, int diff_exp) #else -mpfr_add1(a, b, c, rnd_mode, diff_exp) - mpfr_ptr a; - mpfr_srcptr b; - mpfr_srcptr c; - unsigned char rnd_mode; +mpfr_add1 (a, b, c, rnd_mode, diff_exp) + mpfr_ptr a; + mpfr_srcptr b; + mpfr_srcptr c; + mp_rnd_t rnd_mode; int diff_exp; #endif { @@ -50,39 +54,46 @@ mpfr_add1(a, b, c, rnd_mode, diff_exp) TMP_DECL(marker); TMP_MARK(marker); - ap = MANT(a); - bp = MANT(b); - cp = MANT(c); + ap = MPFR_MANT(a); + bp = MPFR_MANT(b); + cp = MPFR_MANT(c); if (ap == bp) { - bp = (mp_ptr) TMP_ALLOC(ABSSIZE(b) * BYTES_PER_MP_LIMB); - MPN_COPY (bp, ap, ABSSIZE(b)); + bp = (mp_ptr) TMP_ALLOC(MPFR_ABSSIZE(b) * BYTES_PER_MP_LIMB); + MPN_COPY (bp, ap, MPFR_ABSSIZE(b)); if (ap == cp) { cp = bp; } } else if (ap == cp) { - cp = (mp_ptr) TMP_ALLOC (ABSSIZE(c) * BYTES_PER_MP_LIMB); - MPN_COPY(cp, ap, ABSSIZE(c)); + cp = (mp_ptr) TMP_ALLOC (MPFR_ABSSIZE(c) * BYTES_PER_MP_LIMB); + MPN_COPY(cp, ap, MPFR_ABSSIZE(c)); } - an = (PREC(a)-1)/mp_bits_per_limb+1; /* number of significant limbs of a */ + an = (MPFR_PREC(a)-1)/BITS_PER_MP_LIMB+1; /* number of significant limbs of a */ - sh = an*mp_bits_per_limb-PREC(a); /* non-significant bits in low limb */ - bn = (PREC(b)-1)/mp_bits_per_limb+1; /* number of significant limbs of b */ - EXP(a) = EXP(b); + sh = an*BITS_PER_MP_LIMB-MPFR_PREC(a); /* non-significant bits in low limb */ + bn = (MPFR_PREC(b)-1)/BITS_PER_MP_LIMB + 1; /* number of significant limbs of b */ + cn = (MPFR_PREC(c)-1)/BITS_PER_MP_LIMB + 1; + MPFR_EXP(a) = MPFR_EXP(b); - if (SIGN(a)!=SIGN(b)) CHANGE_SIGN(a); + if (MPFR_SIGN(a) * MPFR_SIGN(b) < 0) MPFR_CHANGE_SIGN(a); /* case 1: diff_exp>=prec(a), i.e. c only affects the last bit through rounding */ - dif = PREC(a)-diff_exp; + dif = MPFR_PREC(a)-diff_exp; +#ifdef DEBUG + printf("diff_exp=%u dif=MPFR_PREC(a)-diff_exp=%d\n", diff_exp, dif); + printf("b= "); mpfr_print_raw(b); putchar('\n'); + printf("c="); for (k=0;k<diff_exp;k++) putchar(' '); + if (MPFR_SIGN(c)>0) putchar(' '); mpfr_print_raw(c); putchar('\n'); +#endif if (dif<=0) { - /* diff_exp>=PREC(a): c does not overlap with a */ - /* either PREC(b)<=PREC(a), and we can copy the mantissa of b directly - into that of a, or PREC(b)>PREC(a) and we have to round b+c */ + /* diff_exp>=MPFR_PREC(a): c does not overlap with a */ + /* either MPFR_PREC(b)<=MPFR_PREC(a), and we can copy the mantissa of b directly + into that of a, or MPFR_PREC(b)>MPFR_PREC(a) and we have to round b+c */ - if (PREC(b)<=PREC(a)) { + if (MPFR_PREC(b)<=MPFR_PREC(a)) { MPN_COPY(ap+(an-bn), bp, bn); /* fill low significant limbs with zero */ @@ -93,22 +104,22 @@ mpfr_add1(a, b, c, rnd_mode, diff_exp) if (rnd_mode==GMP_RNDN) { /* to nearest */ - /* if diff_exp > PREC(a), no change */ + /* if diff_exp > MPFR_PREC(a), no change */ - if (diff_exp==PREC(a)) { + if (diff_exp==MPFR_PREC(a)) { /* if c is not zero, then as it is normalized, we have to add one to the lsb of a if c>1/2, or c=1/2 and lsb(a)=1 (round to even) */ - if (NOTZERO(c)) { + if (MPFR_NOTZERO(c)) { /* c is not zero */ /* check whether mant(c)=1/2 or not */ - cc = *cp - (ONE<<(mp_bits_per_limb-1)); + cc = *cp - (ONE<<(BITS_PER_MP_LIMB-1)); if (cc==0) { - bp = cp+(PREC(c)-1)/mp_bits_per_limb; + bp = cp+(MPFR_PREC(c)-1)/BITS_PER_MP_LIMB; while (cp<bp && cc==0) cc = *++cp; } @@ -117,80 +128,88 @@ mpfr_add1(a, b, c, rnd_mode, diff_exp) } } } - else if ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || - (ISNEG(b) && rnd_mode==GMP_RNDD)) { + else if ((MPFR_ISNONNEG(b) && rnd_mode==GMP_RNDU) || + (MPFR_ISNEG(b) && rnd_mode==GMP_RNDD)) { /* round up */ - if (NOTZERO(c)) goto add_one_ulp; + if (MPFR_NOTZERO(c)) goto add_one_ulp; } /* in the other cases (round to zero, or up/down with sign -/+), nothing to do */ } else { - /* PREC(b)>PREC(a) : we have to round b+c */ + /* MPFR_PREC(b)>MPFR_PREC(a) : we have to round b+c */ k=bn-an; /* first copy the 'an' most significant limbs of b to a */ MPN_COPY(ap, bp+k, an); - if (rnd_mode==GMP_RNDN) { - - /* to nearest */ - /* first check whether the truncated bits from b are 1/2*lsb(a) */ - + { /* treat all rounding modes together */ + mp_limb_t c2old; long int cout=0; int sign=0; if (sh) { cc = *ap & ((ONE<<sh)-1); *ap &= ~cc; /* truncate last bits */ - cc -= ONE<<(sh-1); } - else /* no bit to truncate */ - cc = bp[--k] - (ONE<<(mp_bits_per_limb-1)); - - if ((long)cc>0) goto add_one_ulp; /* trunc(b)>1/2*lsb(a) -> round up */ - else if (cc==0) { + else cc=0; - while (k>1 && cc==0) cc=bp[--k]; - - /* now if the truncated part of b = 1/2*lsb(a), check whether c=0 */ - if (NOTZERO(c) || (*ap & (ONE<<sh))) goto add_one_ulp; - /* if trunc(b)+c is exactly 1/2*lsb(a) : round to even lsb */ + dif += sh; + if (dif>0) { + cn--; + c2old = cp[cn]; /* last limb from c considered */ + cout += mpn_add_1(&cc, &cc, 1, c2old >> (BITS_PER_MP_LIMB-dif)); } - - /* if cc<0 : trunc(b) < 1/2*lsb(a) -> round down, i.e. do nothing */ - } - else if ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || - (ISNEG(b) && rnd_mode==GMP_RNDD)) { - - /* first check whether trunc(b)+c is zero or not */ - if (sh) { - cc = *ap & ((ONE<<sh)-1); *ap &= ~cc; /* truncate last bits */ + else c2 = c2old = 0; + if (sh && rnd_mode==GMP_RNDN) + cout -= mpn_sub_1(&cc, &cc, 1, ONE<<(sh-1)); + if (cout==0) { + dif += BITS_PER_MP_LIMB; + while (cout==0 && (k || cn)) { + cout = (cc>(mp_limb_t)1) ? 2 : cc; + cc = (k) ? bp[--k] : 0; + if (sh==0) { + cout -= mpn_sub_1(&cc, &cc, 1, ONE << (BITS_PER_MP_LIMB-1)); + sh = 0; + } + /* next limb from c to consider is cp[cn-1], with lower part of + c2old */ + c2 = c2old << dif; + if (cn && (dif>=0)) { + cn--; + c2old = cp[cn]; + c2 += c2old >> (BITS_PER_MP_LIMB-dif); + } + else dif += BITS_PER_MP_LIMB; + cout += mpn_add_1(&cc, &cc, 1, c2); + } } - else cc = bp[--k] - (ONE<<(mp_bits_per_limb-1)); - while (cc==0 && k>1) cc=bp[--k]; - if (cc || NOTZERO(c)) goto add_one_ulp; + if (cout==0) cout=(cc!=0); + sign = (MPFR_ISNONNEG(b) && rnd_mode==GMP_RNDU) + || (MPFR_ISNEG(b) && rnd_mode==GMP_RNDD) || (rnd_mode==GMP_RNDN); + /* round towards infinity if dif=1, towards zero otherwise */ + if ((sign==1) && (cout>0)) goto add_one_ulp; + else if (rnd_mode==GMP_RNDN && cout==0 && (*ap & (ONE<<sh))) + goto add_one_ulp; } - - /* in the other cases (round to zero, or up/down with sign -/+), - nothing to do, since b and c don't overlap, there can't be any - carry */ - } } else { - /* diff_exp < PREC(a) : c overlaps with a by dif bits */ + /* diff_exp < MPFR_PREC(a) : c overlaps with a by dif bits */ /* first copy upper part of c into a (after shift) */ unsigned char overlap; - k = (dif-1)/mp_bits_per_limb + 1; /* only the highest k limbs from c + k = (dif-1)/BITS_PER_MP_LIMB + 1; /* only the highest k limbs from c have to be considered */ - cn = (PREC(c)-1)/mp_bits_per_limb + 1; + cn = (MPFR_PREC(c)-1)/BITS_PER_MP_LIMB + 1; MPN_ZERO(ap+k, an-k); /* do it now otherwise ap[k] may be destroyed in case dif<0 */ - if (dif<=PREC(c)) { +#ifdef DEBUG + printf("MPFR_PREC(c)=%d\n", MPFR_PREC(c)); +#endif + if (dif<=MPFR_PREC(c)) { /* c has to be truncated */ - dif = dif % mp_bits_per_limb; - dif = (dif) ? mp_bits_per_limb-dif-sh : -sh; + dif = dif % BITS_PER_MP_LIMB; + dif = (dif) ? BITS_PER_MP_LIMB-dif-sh : -sh; /* we have to shift by dif bits to the right */ @@ -201,7 +220,7 @@ mpfr_add1(a, b, c, rnd_mode, diff_exp) /* put the non-significant bits in low limb for further rounding */ if (cn >= k+1) - ap[0] += cp[cn-k-1]>>(mp_bits_per_limb+dif); + ap[0] += cp[cn-k-1]>>(BITS_PER_MP_LIMB+dif); } else MPN_COPY(ap, cp+(cn-k), k); overlap=1; @@ -210,8 +229,8 @@ mpfr_add1(a, b, c, rnd_mode, diff_exp) /* c is not truncated, but we have to fill low limbs with 0 */ - k = diff_exp/mp_bits_per_limb; - overlap = diff_exp%mp_bits_per_limb; + k = diff_exp/BITS_PER_MP_LIMB; + overlap = diff_exp%BITS_PER_MP_LIMB; /* warning: a shift of zero bit is not allowed */ MPN_ZERO(ap, an-k-cn); @@ -227,135 +246,135 @@ mpfr_add1(a, b, c, rnd_mode, diff_exp) /* then put high limbs to zero */ /* now add 'an' upper limbs of b in place */ - if (PREC(b)<=PREC(a)) { + if (MPFR_PREC(b)<=MPFR_PREC(a)) { overlap += 2; cc = mpn_add_n(ap+(an-bn), ap+(an-bn), bp, bn); } else - /* PREC(b) > PREC(a): we have to truncate b */ + /* MPFR_PREC(b) > MPFR_PREC(a): we have to truncate b */ cc = mpn_add_n(ap, ap, bp+(bn-an), an); if (cc) { /* shift one bit to the right */ - c3 = (ap[0]&1) && (PREC(a)%mp_bits_per_limb==0); + c3 = (ap[0]&1) && (MPFR_PREC(a)%BITS_PER_MP_LIMB==0); mpn_rshift(ap, ap, an, 1); - ap[an-1] += ONE<<(mp_bits_per_limb-1); - EXP(a)++; + ap[an-1] += ONE<<(BITS_PER_MP_LIMB-1); + MPFR_EXP(a)++; } /* remains to do the rounding */ - if (rnd_mode==GMP_RNDN) { - - /* to nearest */ +#ifdef DEBUG + printf("overlap=%d\n", overlap); +#endif + if (rnd_mode==GMP_RNDN || (MPFR_ISNONNEG(b) && rnd_mode==GMP_RNDU) + || (MPFR_ISNEG(b) && rnd_mode==GMP_RNDD)) { int kc; /* four cases: overlap = - (0) PREC(b) > PREC(a) and diff_exp+PREC(c) <= PREC(a) - (1) PREC(b) > PREC(a) and diff_exp+PREC(c) > PREC(a) - (2) PREC(b) <= PREC(a) and diff_exp+PREC(c) <= PREC(a) - (3) PREC(b) <= PREC(a) and diff_exp+PREC(c) > PREC(a) */ - + (0) MPFR_PREC(b) > MPFR_PREC(a) and diff_exp+MPFR_PREC(c) <= MPFR_PREC(a) + (1) MPFR_PREC(b) > MPFR_PREC(a) and diff_exp+MPFR_PREC(c) > MPFR_PREC(a) + (2) MPFR_PREC(b) <= MPFR_PREC(a) and diff_exp+MPFR_PREC(c) <= MPFR_PREC(a) + (3) MPFR_PREC(b) <= MPFR_PREC(a) and diff_exp+MPFR_PREC(c) > MPFR_PREC(a) */ + switch (overlap) - { + { mp_limb_t cout; case 1: /* both b and c to round */ kc = cn-k; /* remains kc limbs from c */ k = bn-an; /* remains k limbs from b */ - + /* truncate last bits and store the difference with 1/2*ulp in cc */ cc = *ap & ((ONE<<sh)-1); *ap &= ~cc; /* truncate last bits */ - cc -= ONE<<(sh-1); - while ((cc==0 || cc==-1) && k!=0 && kc!=0) { + if (rnd_mode==GMP_RNDN) + cout = -mpn_sub_1(&cc, &cc, 1, ONE<<(sh-1)); + else cout=0; + if ((~cout==0) && (~cc)) break; + cout = cc; + while ((cout==0 || cout==-1) && k!=0 && kc!=0) { kc--; - cc += mpn_add_1(&c2, bp+(--k), 1,(cp[kc+1]<<(mp_bits_per_limb-dif)) + cout += mpn_add_1(&cc, bp+(--k), 1,(cp[kc+1]<<(BITS_PER_MP_LIMB-dif)) +(cp[kc]>>dif)); - if (cc==0 || cc==-1) cc=c2; + if (cout==0 || (~cout==0)) cout=cc; + } + if (kc==0 && dif) { + /* it still remains cp[0]<<(BITS_PER_MP_LIMB-dif) */ + if (k!=0) cout += mpn_add_1(&cc, bp+(--k), 1, + cp[0]<<(BITS_PER_MP_LIMB-dif)); + else cc = cp[0]<<(BITS_PER_MP_LIMB-dif); + if ((cout==0 && cc==0) || (~cout==0 && ~cc==0)) cout=cc; + } + if ((long)cout>0 || (cout==0 && cc)) goto add_one_ulp; + else if ((long)cout<0) + { TMP_FREE(marker); return; /* no carry possible any more */ } + else if (kc==0) { + while (k && cout==0) cout=bp[--k]; + if ((~cout) && (cout || (rnd_mode==GMP_RNDN && (*ap & (ONE<<sh))))) + goto add_one_ulp; + else goto end_of_add; } - if ((long)cc>0) goto add_one_ulp; - else if ((long)cc<-1) - { TMP_FREE(marker); return; /* the carry can be at most 1 */ } - else if (kc==0) goto round_b; /* else round c: go through */ case 3: /* only c to round */ - bp=cp; k=cn-k; goto to_nearest; + bp=cp; k=cn-k; bn=cn; + goto to_nearest; case 0: /* only b to round */ - round_b: - k=bn-an; dif=0; goto to_nearest; + k=bn-an; dif=0; + goto to_nearest; /* otherwise the result is exact: nothing to do */ } } - else if ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || - (ISNEG(b) && rnd_mode==GMP_RNDD)) { - cc = *ap & ((ONE<<sh)-1); - *ap &= ~cc; /* truncate last bits */ - if (cc || c3) goto add_one_ulp; /* will happen most of the time */ - else { - - /* same four cases too */ - - int kc = cn-k; /* remains kc limbs from c */ - switch (overlap) - { - case 1: /* both b and c to round */ - k = bn-an; /* remains k limbs from b */ - while (cc==0 && k!=0 && kc!=0) { - kc--; - cc = mpn_add_1(&c2, bp+(--k), 1,(cp[kc+1]<<(mp_bits_per_limb-dif)) - + (cp[kc]>>dif)); - } - if (cc) goto add_one_ulp; - else if (kc==0) goto round_b2; - /* else round c: go through */ - case 3: /* only c to round */ - while (kc) if (cp[--kc]) goto add_one_ulp; - /* if dif>0 : remains to check last dif bits from c */ - if (dif>0 && (cp[0]<<(mp_bits_per_limb-dif))) goto add_one_ulp; - break; - case 0: /* only b to round */ - round_b2: - k=bn-an; - while (k) if (bp[--k]) goto add_one_ulp; - /* otherwise the result is exact: nothing to do */ - } - } - } /* else nothing to do: round towards zero, i.e. truncate last sh bits */ else *ap &= ~((ONE<<sh)-1); } goto end_of_add; - to_nearest: /* 0 <= sh < mp_bits_per_limb : number of bits of a to truncate - bp[k] : last significant limb from b */ + to_nearest: /* 0 <= sh < BITS_PER_MP_LIMB : number of bits of a to truncate + bp[k] : last significant limb from b + bn : number of limbs of b + */ + /* c3=1 whenever b+c gave a carry out in most significant limb + and the least significant bit (shifted right) was 1. + This can occur only when BITS_PER_MP_LIMB divides MPFR_PREC(a), + i.e. sh=0. + */ if (sh) { cc = *ap & ((ONE<<sh)-1); *ap &= ~cc; /* truncate last bits */ - c2 = ONE<<(sh-1); + c2 = (rnd_mode==GMP_RNDN) ? ONE<<(sh-1) : 0; } - else /* no bit to truncate */ - { if (k) cc = bp[--k]; else cc = 0; c2 = ONE<<(mp_bits_per_limb-1); } + else /* sh=0: no bit to truncate */ + { + if (k) cc = bp[--k]; else cc = 0; + c2 = (rnd_mode==GMP_RNDN) ? ONE<<(BITS_PER_MP_LIMB-1) : 0; + if (c3 && (cc || c2==0)) cc=c2+1; /* will force adding one ulp */ + } if (cc>c2) goto add_one_ulp; /* trunc(b)>1/2*lsb(a) -> round up */ else if (cc==c2) { - cc=0; while (k && cc==0) cc=bp[--k]; /* special case of rouding c shifted to the right */ - if (cc==0 && dif>0) cc=cp[0]<<(mp_bits_per_limb-dif); + if (dif>0 && k<bn) cc=bp[k]<<(BITS_PER_MP_LIMB-dif); + else cc=0; + while (k && cc==0) cc=bp[--k]; /* now if the truncated part of b = 1/2*lsb(a), check whether c=0 */ - if (cc || (*ap & (ONE<<sh))) goto add_one_ulp; + if (cc || (rnd_mode==GMP_RNDN && (*ap & (ONE<<sh)))) + goto add_one_ulp; } goto end_of_add; add_one_ulp: /* add one unit in last place to a */ cc = mpn_add_1(ap, ap, an, ONE<<sh); - if (cc) { fprintf(stderr, "carry(3) in mpfr_add\n"); exit(1); } + if (cc) { + ap[an-1] = (mp_limb_t)1 << (BITS_PER_MP_LIMB-1); + MPFR_EXP(a)++; + } end_of_add: TMP_FREE(marker); @@ -364,27 +383,57 @@ mpfr_add1(a, b, c, rnd_mode, diff_exp) void #if __STDC__ -mpfr_add(mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, - unsigned char rnd_mode) +mpfr_add (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mp_rnd_t rnd_mode) #else -mpfr_add(a, b, c, rnd_mode) - mpfr_ptr a; - mpfr_srcptr b; - mpfr_srcptr c; - unsigned char rnd_mode; +mpfr_add (a, b, c, rnd_mode) + mpfr_ptr a; + mpfr_srcptr b; + mpfr_srcptr c; + mp_rnd_t rnd_mode; #endif { int diff_exp; - if (FLAG_NAN(b) || FLAG_NAN(c)) { - SET_NAN(a); return; + if (MPFR_IS_NAN(b) || MPFR_IS_NAN(c)) { + MPFR_SET_NAN(a); return; } + + MPFR_CLEAR_NAN(a); + + if (MPFR_IS_INF(b)) + { + if (MPFR_IS_INF(c)) + { + if (MPFR_SIGN(b) == MPFR_SIGN(c)) + { + MPFR_SET_INF(a); + if (MPFR_SIGN(a) != MPFR_SIGN(b)) MPFR_CHANGE_SIGN(a); + } + else + MPFR_SET_NAN(a); + } + else + { + MPFR_SET_INF(a); + if (MPFR_SIGN(b) != MPFR_SIGN(a)) MPFR_CHANGE_SIGN(a); + } + return; + } + else + if (MPFR_IS_INF(c)) + { + MPFR_SET_INF(a); + if (MPFR_SIGN(c) != MPFR_SIGN(a)) MPFR_CHANGE_SIGN(a); + return; + } + + MPFR_CLEAR_INF(a); /* clear Inf flag */ - if (!NOTZERO(b)) { mpfr_set(a, c, rnd_mode); return; } - if (!NOTZERO(c)) { mpfr_set(a, b, rnd_mode); return; } + if (!MPFR_NOTZERO(b)) { mpfr_set(a, c, rnd_mode); return; } + if (!MPFR_NOTZERO(c)) { mpfr_set(a, b, rnd_mode); return; } - diff_exp = EXP(b)-EXP(c); - if (SIGN(b) != SIGN(c)) { /* signs differ, it's a subtraction */ + diff_exp = MPFR_EXP(b)-MPFR_EXP(c); + if (MPFR_SIGN(b) * MPFR_SIGN(c) < 0) { /* signs differ, it's a subtraction */ if (diff_exp<0) { mpfr_sub1(a, c, b, rnd_mode, -diff_exp); } @@ -392,8 +441,8 @@ mpfr_add(a, b, c, rnd_mode) else { /* diff_exp=0 */ diff_exp = mpfr_cmp3(b,c,-1); /* if b>0 and diff_exp>0 or b<0 and diff_exp<0: abs(b) > abs(c) */ - if (diff_exp==0) SET_ZERO(a); - else if (diff_exp*SIGN(b)>0) mpfr_sub1(a, b, c, rnd_mode, 0); + if (diff_exp==0) MPFR_SET_ZERO(a); + else if (diff_exp * MPFR_SIGN(b)>0) mpfr_sub1(a, b, c, rnd_mode, 0); else mpfr_sub1(a, c, b, rnd_mode, 0); } } diff --git a/mpfr/add_ui.c b/mpfr/add_ui.c new file mode 100644 index 000000000..43c08e316 --- /dev/null +++ b/mpfr/add_ui.c @@ -0,0 +1,54 @@ +/* mpfr_add_ui -- add a floating-point number with a machine integer + +Copyright (C) 2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +void +#if __STDC__ +mpfr_add_ui (mpfr_ptr y, mpfr_srcptr x, unsigned long int u, mp_rnd_t rnd_mode) +#else +mpfr_add_ui (y, x, u, rnd_mode) + mpfr_ptr y; + mpfr_srcptr x; + unsigned long int u; + mp_rnd_t rnd_mode; +#endif +{ + mpfr_t uu; + mp_limb_t up[1]; + unsigned long cnt; + + if (u) { /* if u=0, do nothing */ + MPFR_INIT1(up, uu, BITS_PER_MP_LIMB, 1); + count_leading_zeros(cnt, (mp_limb_t) u); + *up = (mp_limb_t) u << cnt; + MPFR_EXP(uu) = BITS_PER_MP_LIMB-cnt; + + mpfr_add(y, x, uu, rnd_mode); + } + else + mpfr_set (y, x, rnd_mode); +} diff --git a/mpfr/add_ulp.c b/mpfr/add_ulp.c index 7a8fa6150..d94fd73b6 100644 --- a/mpfr/add_ulp.c +++ b/mpfr/add_ulp.c @@ -1,6 +1,6 @@ /* mpfr_add_one_ulp, mpfr_sub_one_ulp -- add/subtract one unit in last place -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -20,11 +20,12 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gmp.h" -#include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" +#include "gmp-impl.h" -/* sets x to x+sign(x)*2^(EXP(x)-PREC(x)) */ -int +/* sets x to x+sign(x)*2^(MPFR_EXP(x)-MPFR_PREC(x)) */ +void #if __STDC__ mpfr_add_one_ulp(mpfr_ptr x) #else @@ -34,31 +35,34 @@ mpfr_add_one_ulp(x) { int xn, sh; mp_limb_t *xp; - xn = 1 + (PREC(x)-1)/BITS_PER_MP_LIMB; - sh = xn*BITS_PER_MP_LIMB - PREC(x); - xp = MANT(x); + if (MPFR_IS_INF(x)) { return; } + xn = 1 + (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB; + sh = xn*BITS_PER_MP_LIMB - MPFR_PREC(x); + xp = MPFR_MANT(x); if (mpn_add_1(xp, xp, xn, (mp_limb_t)1<<sh)) { - EXP(x)++; + MPFR_EXP(x)++; mpn_rshift(xp, xp, xn, 1); xp[xn-1] += (mp_limb_t)1<<(BITS_PER_MP_LIMB-1); } - return 0; + return; } /* sets x to x-sign(x)*ulp(x) */ -int mpfr_sub_one_ulp(mpfr_ptr x) +void +mpfr_sub_one_ulp(mpfr_ptr x) { int xn, sh; mp_limb_t *xp; - xn = 1 + (PREC(x)-1)/BITS_PER_MP_LIMB; - sh = xn*BITS_PER_MP_LIMB-PREC(x); - xp = MANT(x); + if (MPFR_IS_INF(x)) { return; } + xn = 1 + (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB; + sh = xn*BITS_PER_MP_LIMB-MPFR_PREC(x); + xp = MPFR_MANT(x); mpn_sub_1(xp, xp, xn, (mp_limb_t)1<<sh); if (xp[xn-1] >> (BITS_PER_MP_LIMB-1) == 0) { /* was an exact power of two: not normalized any more */ - EXP(x)--; + MPFR_EXP(x)--; mpn_lshift(xp, xp, xn, 1); *xp |= ((mp_limb_t)1 << sh); } - return 0; + return; } diff --git a/mpfr/agm.c b/mpfr/agm.c index e4c700961..75b5762d3 100644 --- a/mpfr/agm.c +++ b/mpfr/agm.c @@ -1,6 +1,6 @@ /* mpfr_agm -- arithmetic-geometric mean of two floating-point numbers -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -20,72 +20,105 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <stdio.h> -#include <math.h> #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" +/* returns ceil(log(d)/log(2)) */ +long _mpfr_ceil_log2 (double d) +{ + long exp; + union ieee_double_extract x; + + x.d = d; + exp = x.s.exp - 1023; + x.s.exp = 1023; /* value for 1 <= d < 2 */ + if (x.d != 1.0) exp++; + return exp; +} -/*Memory gestion */ -#define MON_INIT(xp, x, p, s) xp = (mp_ptr) TMP_ALLOC(s*BYTES_PER_MP_LIMB); x -> _mp_prec = p; x -> _mp_d = xp; x -> _mp_size = s; x -> _mp_exp = 0; - +/* returns floor(log(d)/log(2)) */ +long _mpfr_floor_log2 (double d) +{ + union ieee_double_extract x; + x.d = d; + return (long) x.s.exp - 1023; +} +/* returns y >= 2^d */ +double _mpfr_ceil_exp2 (double d) +{ + long exp; + union ieee_double_extract x; + + exp = (long) d; + if (d != (double) exp) exp++; + /* now exp = ceil(d) */ + x.d = 1.0; + x.s.exp = 1023 + exp; + return x.d; +} void #ifdef __STDC__ -mpfr_agm(mpfr_ptr r, mpfr_srcptr op2, mpfr_srcptr op1, unsigned char rnd_mode) +mpfr_agm (mpfr_ptr r, mpfr_srcptr op2, mpfr_srcptr op1, mp_rnd_t rnd_mode) #else -mpfr_agm(r, a, b, rnd_mode) - mpfr_ptr r; - mpfr_srcptr a; - mpfr_srcptr b; - unsigned char rnd_mode; +mpfr_agm (r, op2, op1, rnd_mode) + mpfr_ptr r; + mpfr_srcptr op2; + mpfr_srcptr op1; + mp_rnd_t rnd_mode; #endif { - int s, p, q, go_on; + int s, go_on; + mp_prec_t p, q; double uo, vo; mp_limb_t *up, *vp, *tmpp, *tmpup, *tmpvp, *ap, *bp; mpfr_t u, v, tmp, tmpu, tmpv, a, b; TMP_DECL(marker1); TMP_DECL(marker2); - /* If a or b is NaN, the result is NaN */ - if (FLAG_NAN(op1) || FLAG_NAN(op2)) - { SET_NAN(r); return; } + if (MPFR_IS_NAN(op1) || MPFR_IS_NAN(op2)) + { MPFR_SET_NAN(r); return; } + /* If a or b is negative (including -Infinity), the result is NaN */ + if ((MPFR_SIGN(op1) < 0) || (MPFR_SIGN(op2) < 0)) + { MPFR_SET_NAN(r); return; } - /* If a or b is negative, the result is NaN */ - if ((SIGN(op1)<0)||(SIGN(op2)<0)) - { SET_NAN(r); return; } + MPFR_CLEAR_NAN(r); + /* If a or b is +Infinity, the result is +Infinity */ + if (MPFR_IS_INF(op1) || MPFR_IS_INF(op2)) + { MPFR_SET_INF(r); MPFR_SET_SAME_SIGN(r, op1); return; } + MPFR_CLEAR_INF(r); /* If a or b is 0, the result is 0 */ - if ((SIGN(op1)==0)||(SIGN(op2)==0)) - { SET_ZERO(r); + if ((MPFR_NOTZERO(op1) && MPFR_NOTZERO(op2)) == 0) + { MPFR_SET_ZERO(r); return; } /* precision of the following calculus */ - q = PREC(r); + q = MPFR_PREC(r); p = q + 15; - /* Initialisations */ go_on=1; TMP_MARK(marker1); s=(p-1)/BITS_PER_MP_LIMB+1; - MON_INIT(ap, a, p, s); - MON_INIT(bp, b, p, s); + MPFR_INIT(ap, a, p, s); + MPFR_INIT(bp, b, p, s); TMP_MARK(marker2); - MON_INIT(up, u, p, s); - MON_INIT(vp, v, p, s); - MON_INIT(tmpup, tmpu, p, s); - MON_INIT(tmpvp, tmpv, p, s); - MON_INIT(tmpp, tmp, p, s); + MPFR_INIT(up, u, p, s); + MPFR_INIT(vp, v, p, s); + MPFR_INIT(tmpup, tmpu, p, s); + MPFR_INIT(tmpvp, tmpv, p, s); + MPFR_INIT(tmpp, tmp, p, s); @@ -111,16 +144,19 @@ mpfr_agm(r, a, b, rnd_mode) eq=0; - err=ceil((3.0/2.0*log((double)p)/log(2.0)+1.0)*exp(-(double)p*log(2.0))+3.0*exp(-2.0*(double)p*uo*log(2.0)/(vo-uo))); + err=1 + (int) ((3.0/2.0*_mpfr_ceil_log2(p)+1.0)*_mpfr_ceil_exp2(-(double)p) + +3.0*_mpfr_ceil_exp2(-2.0*(double)p*uo/(vo-uo))); if(p-err-3<=q) { p=q+err+4; - err=ceil((3.0/2.0*log((double)p)/log(2.0)+1.0)*exp(-(double)p*log(2.0))+3.0*exp(-2.0*(double)p*uo*log(2.0)/(vo-uo))); + err= 1 + + (int) ((3.0/2.0*_mpfr_ceil_log2(p)+1.0)*_mpfr_ceil_exp2(-(double)p) + +3.0*_mpfr_ceil_exp2(-2.0*(double)p*uo/(vo-uo))); } /* Calculus of un and vn */ while (eq<=p-2) { mpfr_mul(tmp,u,v,GMP_RNDN); - mpfr_sqrt(tmpu,tmp,GMP_RNDN); + mpfr_sqrt (tmpu, tmp, GMP_RNDN); mpfr_add(tmp,u,v,GMP_RNDN); mpfr_div_2exp(tmpv,tmp,1,GMP_RNDN); mpfr_set(u,tmpu,GMP_RNDN); @@ -148,11 +184,11 @@ mpfr_agm(r, a, b, rnd_mode) TMP_FREE(marker2); TMP_MARK(marker2); s=(p-1)/BITS_PER_MP_LIMB+1; - MON_INIT(up, u, p, s); - MON_INIT(vp, v, p, s); - MON_INIT(tmpup, tmpu, p, s); - MON_INIT(tmpvp, tmpv, p, s); - MON_INIT(tmpp, tmp, p, s); + MPFR_INIT(up, u, p, s); + MPFR_INIT(vp, v, p, s); + MPFR_INIT(tmpup, tmpu, p, s); + MPFR_INIT(tmpvp, tmpv, p, s); + MPFR_INIT(tmpp, tmp, p, s); mpfr_set(u,a,GMP_RNDN); mpfr_set(v,b,GMP_RNDN); } diff --git a/mpfr/clear.c b/mpfr/clear.c index dfa4771c5..5f492badf 100644 --- a/mpfr/clear.c +++ b/mpfr/clear.c @@ -1,6 +1,6 @@ /* mpfr_clear -- free the memory space allocated for a floating-point number -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -23,6 +23,7 @@ MA 02111-1307, USA. */ #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" void #if __STDC__ @@ -32,5 +33,6 @@ mpfr_clear (m) mpfr_ptr m; #endif { - (*__gmp_free_func) (m->_mp_d, ((m->_mp_prec>>3) + 1)); + /* be careful to always free an entire number of limbs */ + (*_mp_free_func) (MPFR_MANT(m), MPFR_ABSSIZE(m) * BYTES_PER_MP_LIMB); } diff --git a/mpfr/cmp.c b/mpfr/cmp.c index b64506b03..d0cb175db 100644 --- a/mpfr/cmp.c +++ b/mpfr/cmp.c @@ -1,6 +1,6 @@ /* mpfr_cmp -- compare two floating-point numbers -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -24,6 +24,7 @@ MA 02111-1307, USA. */ #include "gmp-impl.h" #include "longlong.h" #include "mpfr.h" +#include "mpfr-impl.h" /* returns 0 iff b = c a positive value iff b > c @@ -41,9 +42,9 @@ of b and c, i.e. one plus the number of bits shifts to align b and c /* compares b and sign(s)*c */ int #if __STDC__ -mpfr_cmp3 ( mpfr_srcptr b, mpfr_srcptr c, long int s) +mpfr_cmp3 (mpfr_srcptr b, mpfr_srcptr c, long int s) #else -mpfr_cmp3(b, c, s) +mpfr_cmp3 (b, c, s) mpfr_srcptr b; mpfr_srcptr c; long int s; @@ -53,22 +54,34 @@ mpfr_cmp3(b, c, s) unsigned long bn, cn; mp_limb_t *bp, *cp; - if (!NOTZERO(b) && !NOTZERO(c)) { return 0; } - s = s*SIGN(b)*SIGN(c); - if (s<0) return(SIGN(b)); + if (MPFR_IS_NAN(b) || MPFR_IS_NAN(c)) return 1; - /* now signs are equal */ + if (MPFR_IS_INF(b)) { + if (MPFR_IS_INF(c) && (MPFR_SIGN(b) * s * MPFR_SIGN(c) > 0)) + return 0; + else + return MPFR_SIGN(b); + } + + if (!MPFR_NOTZERO(b)) { + if (!MPFR_NOTZERO(c)) return 0; else return -(s*MPFR_SIGN(c)); + } + else if (!MPFR_NOTZERO(c)) return MPFR_SIGN(b); - diff_exp = EXP(b)-EXP(c); - s = (SIGN(b)>0) ? 1 : -1; + s = s * MPFR_SIGN(b) * MPFR_SIGN(c); + if (s<0) return(MPFR_SIGN(b)); + + /* now signs are equal */ + diff_exp = MPFR_EXP(b)-MPFR_EXP(c); + s = (MPFR_SIGN(b) > 0) ? 1 : -1; if (diff_exp>0) return(s*(1+diff_exp)); else if (diff_exp<0) return(s*(-1+diff_exp)); /* both signs and exponents are equal */ - bn = (PREC(b)-1)/mp_bits_per_limb+1; - cn = (PREC(c)-1)/mp_bits_per_limb+1; - bp = MANT(b); cp = MANT(c); + bn = (MPFR_PREC(b)-1)/BITS_PER_MP_LIMB+1; + cn = (MPFR_PREC(c)-1)/BITS_PER_MP_LIMB+1; + bp = MPFR_MANT(b); cp = MPFR_MANT(c); while (bn && cn) { if (bp[--bn] != cp[--cn]) @@ -82,8 +95,10 @@ mpfr_cmp3(b, c, s) } /* returns the number of cancelled bits when one subtracts abs(c) from abs(b). - Assumes b>=c, which implies EXP(b)>=EXP(c). + Assumes b>=c, which implies MPFR_EXP(b)>=MPFR_EXP(c). if b=c, returns prec(b). + + In other terms mpfr_cmp2 (b, c) returns EXP(b) - EXP(b-c). */ int #if __STDC__ @@ -101,44 +116,45 @@ mpfr_cmp2(b, c) printf("b="); mpfr_print_raw(b); putchar('\n'); printf("c="); mpfr_print_raw(c); putchar('\n'); #endif - if (NOTZERO(c)==0) return (NOTZERO(b)) ? 0 : PREC(b); - d = EXP(b)-EXP(c); + if (MPFR_NOTZERO(c)==0) return (MPFR_NOTZERO(b)) ? 0 : MPFR_PREC(b); + d = MPFR_EXP(b)-MPFR_EXP(c); k = 0; /* result can be d or d+1 if d>1, or >= d otherwise */ /* k is the number of identical bits in the high part, then z is the number of possibly cancelled bits */ #ifdef DEBUG - if (d<0) { printf("assumption EXP(b)<EXP(c) violated\n"); exit(1); } + printf("d=%u\n", d); + if (d<0) { printf("assumption MPFR_EXP(b)<MPFR_EXP(c) violated\n"); exit(1); } #endif - bn = (PREC(b)-1)/mp_bits_per_limb; - cn = (PREC(c)-1)/mp_bits_per_limb; - bp = MANT(b); cp = MANT(c); + bn = (MPFR_PREC(b)-1)/BITS_PER_MP_LIMB; + cn = (MPFR_PREC(c)-1)/BITS_PER_MP_LIMB; + bp = MPFR_MANT(b); cp = MPFR_MANT(c); /* subtract c from b from most significant to less significant limbs, and first determines first non zero limb difference */ if (d) { cc = bp[bn--]; - if (d<mp_bits_per_limb) - cc -= cp[cn]>>d; + if (d < BITS_PER_MP_LIMB) + cc -= cp[cn] >> d; } else { /* d=0 */ while (bn>=0 && cn>=0 && (cc=(bp[bn--]-cp[cn--]))==0) { - k+=mp_bits_per_limb; + k+=BITS_PER_MP_LIMB; } if (cc==0) { /* either bn<0 or cn<0 */ - while (bn>=0 && (cc=bp[bn--])==0) k+=mp_bits_per_limb; + while (bn>=0 && (cc=bp[bn--])==0) k+=BITS_PER_MP_LIMB; } /* now bn<0 or cc<>0 */ - if (cc==0 && bn<0) return(PREC(b)); + if (cc==0 && bn<0) return(MPFR_PREC(b)); } /* the first non-zero limb difference is cc, and the number of cancelled bits in the upper limbs is k */ count_leading_zeros(u, cc); - k += u; + k += u; - if (cc != (1<<(mp_bits_per_limb-u-1))) return k; + if (cc != ((mp_limb_t) 1 << (BITS_PER_MP_LIMB - u - 1))) return k; /* now cc is an exact power of two */ if (cc != 1) @@ -151,11 +167,11 @@ mpfr_cmp2(b, c) { if (cn < 0) { return k; } t = bp[bn--]; - if (d < mp_bits_per_limb) + if (d < BITS_PER_MP_LIMB) { if (d) { - u = cp[cn--] << (mp_bits_per_limb - d); + u = cp[cn--] << (BITS_PER_MP_LIMB - d); if (cn >= 0) u+=(cp[cn]>>d); } else u = cp[cn--]; @@ -164,12 +180,12 @@ mpfr_cmp2(b, c) if (t < u) return k+1; } else - if (t) return k; else d -= mp_bits_per_limb; + if (t) return k; else d -= BITS_PER_MP_LIMB; } /* bn < 0; if some limb of c is nonzero, return k+1, otherwise return k*/ - if (cn>=0 && (cp[cn--] << (mp_bits_per_limb - d))) { return k+1; } + if (cn>=0 && (cp[cn--] << (BITS_PER_MP_LIMB - d))) { return k+1; } while (cn >= 0) if (cp[cn--]) return k+1; @@ -180,16 +196,18 @@ mpfr_cmp2(b, c) z = 0; /* number of possibly cancelled bits - 1 */ /* thus result is either k if low(b) >= low(c) or k+z+1 if low(b) < low(c) */ - if (d > mp_bits_per_limb) { return k; } + if (d > BITS_PER_MP_LIMB) return k; - while (bn >= 0) + while (bn >= 0) /* the next limb of b to be considered is b[bn] */ { - if (cn < 0) { return k; } + /* for c we have to consider the low d bits of c[cn] + and the high (BITS_PER_MP_LIMB-d) bits of c[cn-1] */ + if (cn < 0) return k; if (d) { - u = cp[cn--] << (mp_bits_per_limb - d); - if (cn >= 0) u+=(cp[cn]>>d); + u = cp[cn--] << (BITS_PER_MP_LIMB - d); + if (cn >= 0) u += cp[cn] >> d; } else u = cp[cn--]; @@ -198,21 +216,30 @@ mpfr_cmp2(b, c) bp[bn--] < cp[cn--] : borrow */ if ((cc = bp[bn--]) != u) { - if (cc>u) return k; - else { count_leading_zeros(u, cc-u); return k + 1 + z + u; } + if (cc > u) return k; + else { + count_leading_zeros(u, cc-u); + z += u + 1; + if (u + 1 < BITS_PER_MP_LIMB) return k + z; + } } - else z += mp_bits_per_limb; + else z += BITS_PER_MP_LIMB; } - if (cn >= 0) - count_leading_zeros(cc, ~(cp[cn--] << (mp_bits_per_limb - d))); - else { cc = 0; } + /* warning: count_leading_zeros doesn't work with zero */ + if ((cn >= 0) && d && (u = ~(cp[cn--] << (BITS_PER_MP_LIMB - d)))) + count_leading_zeros(cc, u); + else + cc = 0; - k += cc; + /* here d=0 or d=1: if d=1, we have one more cancelled bit if we don't + shift cp[cn] */ + k += cc; if (cc < d) return k; - while (cn >= 0 && !~cp[cn--]) { z += mp_bits_per_limb; } - if (cn >= 0) { count_leading_zeros(cc, ~cp[cn--]); return (k + z + cc); } + while (cn >= 0 && !~cp[cn]) { z += BITS_PER_MP_LIMB; cn--; } + /* now either cn<0 or cp[cn] is not 111...111 */ + if (cn >= 0) { count_leading_zeros(cc, ~cp[cn]); return (k + 1 + z + cc); } return k; /* We **need** that the nonsignificant limbs of c are set to zero there */ diff --git a/mpfr/cmp_ui.c b/mpfr/cmp_ui.c index 48217a520..364881970 100644 --- a/mpfr/cmp_ui.c +++ b/mpfr/cmp_ui.c @@ -1,6 +1,6 @@ /* mpfr_cmp_ui -- compare a floating-point number with a machine integer -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -24,6 +24,7 @@ MA 02111-1307, USA. */ #include "gmp-impl.h" #include "longlong.h" #include "mpfr.h" +#include "mpfr-impl.h" /* returns a positive value if b>i*2^f, a negative value if b<i*2^f, @@ -32,7 +33,7 @@ MA 02111-1307, USA. */ int #if __STDC__ -mpfr_cmp_ui_2exp ( mpfr_srcptr b, unsigned long int i, int f ) +mpfr_cmp_ui_2exp (mpfr_srcptr b, unsigned long int i, int f ) #else mpfr_cmp_ui_2exp (b, i, f) mpfr_srcptr b; @@ -42,21 +43,27 @@ mpfr_cmp_ui_2exp (b, i, f) { int e, k, bn; mp_limb_t c, *bp; - if (SIGN(b)<0) return -1; - else if (!NOTZERO(b)) return((i) ? -1 : 0); - else { /* b>0 */ - e = EXP(b); /* 2^(e-1) <= b < 2^e */ - if (e>f+mp_bits_per_limb) return 1; + if (MPFR_IS_NAN(b)) return 1; + + if (MPFR_SIGN(b) < 0) return -1; + /* now b>=0 */ + else if (MPFR_IS_INF(b)) return 1; + else if (!MPFR_NOTZERO(b)) return((i) ? -1 : 0); + /* now b>0 */ + else if (i==0) return 1; + else { /* b>0, i>0 */ + e = MPFR_EXP(b); /* 2^(e-1) <= b < 2^e */ + if (e>f+BITS_PER_MP_LIMB) return 1; c = (mp_limb_t) i; count_leading_zeros(k, c); - k = f+mp_bits_per_limb - k; /* 2^(k-1) <= i*2^f < 2^k */ + k = f+BITS_PER_MP_LIMB - k; /* 2^(k-1) <= i*2^f < 2^k */ if (k!=e) return (e-k); /* now k=e */ - c <<= (f+mp_bits_per_limb-k); - bn = (PREC(b)-1)/mp_bits_per_limb; - bp = MANT(b) + bn; + c <<= (f+BITS_PER_MP_LIMB-k); + bn = (MPFR_PREC(b)-1)/BITS_PER_MP_LIMB; + bp = MPFR_MANT(b) + bn; if (*bp>c) return 1; else if (*bp<c) return -1; @@ -74,9 +81,9 @@ mpfr_cmp_ui_2exp (b, i, f) int #if __STDC__ -mpfr_cmp_si_2exp ( mpfr_srcptr b, long int i, int f ) +mpfr_cmp_si_2exp (mpfr_srcptr b, long int i, int f ) #else -mpfr_cmp_si_2exp(b, i, f) +mpfr_cmp_si_2exp (b, i, f) mpfr_srcptr b; long int i; int f; @@ -84,26 +91,29 @@ mpfr_cmp_si_2exp(b, i, f) { int e, k, bn, si; mp_limb_t c, *bp; + if (MPFR_IS_NAN(b)) return 1; + si = (i<0) ? -1 : 1; /* sign of i */ - if (SIGN(b)*i<0) return SIGN(b); /* both signs differ */ - else if (!NOTZERO(b) || (i==0)) { /* one is zero */ - if (i==0) return ((NOTZERO(b)) ? SIGN(b) : 0); + if (MPFR_SIGN(b) * i < 0 || MPFR_IS_INF(b)) return MPFR_SIGN(b); + /* both signs differ */ + else if (!MPFR_NOTZERO(b) || (i==0)) { /* one is zero */ + if (i==0) return ((MPFR_NOTZERO(b)) ? MPFR_SIGN(b) : 0); else return si; /* b is zero */ } else { /* b and i are of same sign */ - e = EXP(b); /* 2^(e-1) <= b < 2^e */ - if (e>f+mp_bits_per_limb) return si; + e = MPFR_EXP(b); /* 2^(e-1) <= b < 2^e */ + if (e>f+BITS_PER_MP_LIMB) return si; c = (mp_limb_t) ((i<0) ? -i : i); count_leading_zeros(k, c); - k = f+mp_bits_per_limb - k; /* 2^(k-1) <= i*2^f < 2^k */ + k = f+BITS_PER_MP_LIMB - k; /* 2^(k-1) <= i*2^f < 2^k */ if (k!=e) return (si*(e-k)); /* now k=e */ - c <<= (f+mp_bits_per_limb-k); - bn = (PREC(b)-1)/mp_bits_per_limb; - bp = MANT(b) + bn; + c <<= (f+BITS_PER_MP_LIMB-k); + bn = (MPFR_PREC(b)-1)/BITS_PER_MP_LIMB; + bp = MPFR_MANT(b) + bn; if (*bp>c) return si; else if (*bp<c) return -si; diff --git a/mpfr/cputime.h b/mpfr/cputime.h new file mode 100644 index 000000000..69d49620f --- /dev/null +++ b/mpfr/cputime.h @@ -0,0 +1,25 @@ +/* Return user CPU time measured in milliseconds. Thanks to Torbjorn. */ + +int cputime _PROTO((void)); + +#if defined (ANSIONLY) || defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined(__hpux) +#include <time.h> + +int +cputime () +{ + return (int) ((double) clock () * 1000 / CLOCKS_PER_SEC); +} +#else +#include <sys/types.h> +#include <sys/resource.h> + +int +cputime () +{ + struct rusage rus; + + getrusage (0, &rus); + return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000; +} +#endif diff --git a/mpfr/div.c b/mpfr/div.c index ee1475694..bf5ffc371 100644 --- a/mpfr/div.c +++ b/mpfr/div.c @@ -1,6 +1,6 @@ /* mpfr_div -- divide two floating-point numbers -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -19,53 +19,91 @@ along with the MPFR Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include <math.h> #include <stdio.h> #include <stdlib.h> #include "gmp.h" #include "gmp-impl.h" -#include "mpfr.h" #include "longlong.h" +#include "mpfr.h" +#include "mpfr-impl.h" /* #define DEBUG */ void -mpfr_div (mpfr_ptr r, mpfr_srcptr u, mpfr_srcptr v, unsigned char rnd_mode) +#if __STDC__ +mpfr_div (mpfr_ptr r, mpfr_srcptr u, mpfr_srcptr v, mp_rnd_t rnd_mode) +#else +mpfr_div (r, u, v, rnd_mode) + mpfr_ptr r; + mpfr_srcptr u; + mpfr_srcptr v; + mp_rnd_t rnd_mode; +#endif { mp_srcptr up, vp; - mp_ptr rp, tp, tp0, tmp; - mp_size_t usize, vsize, rrsize; + mp_ptr rp, tp, tp0, tmp, tmp2; + mp_size_t usize, vsize, rrsize, oldrrsize; mp_size_t rsize; mp_size_t sign_quotient; mp_size_t prec, err; mp_limb_t q_limb; mp_exp_t rexp; - long k, mult, vn; + long k, mult, vn, t; unsigned long cc = 0, rw, nw; char can_round = 0; TMP_DECL (marker); - if (FLAG_NAN(u) || FLAG_NAN(v)) { SET_NAN(r); return; } - - usize = (PREC(u) - 1)/BITS_PER_MP_LIMB + 1; - vsize = (PREC(v) - 1)/BITS_PER_MP_LIMB + 1; - sign_quotient = (SIGN(u) == SIGN(v) ? 1 : -1); - prec = PREC(r); + if (MPFR_IS_NAN(u) || MPFR_IS_NAN(v)) { MPFR_SET_NAN(r); return; } - if (!NOTZERO(u)) { SET_ZERO(r); return; } + MPFR_CLEAR_NAN(r); - if (!NOTZERO(v)) - vsize = 1 / v->_mp_d[vsize - 1]; /* Gestion des infinis ? */ - - if (!NOTZERO(v)) - { - r->_mp_exp = 0; - MPN_ZERO(r->_mp_d, r->_mp_size); + if (MPFR_IS_INF(u)) + { + if (MPFR_IS_INF(v)) + MPFR_SET_NAN(r); + else + { + MPFR_SET_INF(r); + if (MPFR_SIGN(r) != MPFR_SIGN(u) * MPFR_SIGN(v)) + MPFR_CHANGE_SIGN(r); + } return; } + else + if (MPFR_IS_INF(v)) + { + MPFR_CLEAR_INF(r); + MPFR_SET_ZERO(r); + if (MPFR_SIGN(r) != MPFR_SIGN(u) * MPFR_SIGN(v)) + MPFR_CHANGE_SIGN(r); + return; + } + + MPFR_CLEAR_INF(r); /* clear Inf flag */ + + usize = (MPFR_PREC(u) - 1)/BITS_PER_MP_LIMB + 1; + vsize = (MPFR_PREC(v) - 1)/BITS_PER_MP_LIMB + 1; + sign_quotient = ((MPFR_SIGN(u) * MPFR_SIGN(v) > 0) ? 1 : -1); + prec = MPFR_PREC(r); - up = u->_mp_d; - vp = v->_mp_d; + + if (!MPFR_NOTZERO(v)) + { + if (!MPFR_NOTZERO(u)) + { MPFR_SET_NAN(r); return; } + else + { + MPFR_SET_INF(r); + if (MPFR_SIGN(r) != MPFR_SIGN(v) * MPFR_SIGN(u)) + MPFR_CHANGE_SIGN(r); + return; + } + } + + if (!MPFR_NOTZERO(u)) { MPFR_SET_ZERO(r); return; } + + up = MPFR_MANT(u); + vp = MPFR_MANT(v); #ifdef DEBUG printf("Entering division : "); @@ -85,19 +123,17 @@ mpfr_div (mpfr_ptr r, mpfr_srcptr u, mpfr_srcptr v, unsigned char rnd_mode) } else { mult = (mult < 0 ? 1 : 0); } - rsize = (PREC(r) + 3)/BITS_PER_MP_LIMB + 1; - rrsize = PREC(r)/BITS_PER_MP_LIMB + 1; + rsize = (MPFR_PREC(r) + 3)/BITS_PER_MP_LIMB + 1; + rrsize = MPFR_PREC(r)/BITS_PER_MP_LIMB + 1; /* Three extra bits are needed in order to get the quotient with enough precision ; take one extra bit for rrsize in order to solve more easily the problem of rounding to nearest. */ - /* ATTENTION, USIZE DOIT RESTER > A VSIZE !!!!!!!! */ - do { TMP_MARK (marker); - rexp = u->_mp_exp - v->_mp_exp; + rexp = MPFR_EXP(u) - MPFR_EXP(v); err = rsize*BITS_PER_MP_LIMB; if (rsize < vsize) { err-=2; } @@ -108,13 +144,13 @@ mpfr_div (mpfr_ptr r, mpfr_srcptr u, mpfr_srcptr v, unsigned char rnd_mode) tp0 = (mp_ptr) TMP_ALLOC ((rsize+rrsize) * BYTES_PER_MP_LIMB); /* fill by zero rrsize low limbs of t */ MPN_ZERO(tp0, rrsize); tp = tp0 + rrsize; - tmp = (mp_ptr) TMP_ALLOC (rsize * BYTES_PER_MP_LIMB); - rp = (mp_ptr) TMP_ALLOC (rrsize * BYTES_PER_MP_LIMB); + rp = (mp_ptr) TMP_ALLOC ((rrsize+1) * BYTES_PER_MP_LIMB); if (vsize >= rsize) { - MPN_COPY (tmp, vp + vsize - rsize, rsize); + tmp = (mp_ptr) vp + vsize - rsize; } else { + tmp = (mp_ptr) TMP_ALLOC (rsize * BYTES_PER_MP_LIMB); MPN_COPY (tmp + rsize - vsize, vp, vsize); MPN_ZERO (tmp, rsize - vsize); } @@ -137,10 +173,15 @@ mpfr_div (mpfr_ptr r, mpfr_srcptr u, mpfr_srcptr v, unsigned char rnd_mode) printf(".\n"); #endif - q_limb = (rsize==rrsize) /* use Burnikel-Ziegler algorithm */ - ? mpn_divrem_n (rp, tp0, tmp, rsize) - : mpn_divrem (rp, 0, tp0, rsize+rrsize, tmp, rsize); +#if (__GNU_MP_VERSION < 3) + q_limb = mpn_divrem (rp, 0, tp0, rsize+rrsize, tmp, rsize); tp = tp0; /* location of remainder */ +#else /* mpn_tdiv_qr is the preferred division interface in GMP 3 */ + tmp2 = (mp_ptr) TMP_ALLOC (rsize * BYTES_PER_MP_LIMB); + mpn_tdiv_qr(rp, tmp2, 0, tp0, rsize+rrsize, tmp, rsize); + q_limb = rp[rrsize]; + tp = tmp2; /* location of remainder */ +#endif #ifdef DEBUG printf("The result is : \n"); @@ -156,8 +197,8 @@ mpfr_div (mpfr_ptr r, mpfr_srcptr u, mpfr_srcptr v, unsigned char rnd_mode) if (q_limb) { count_leading_zeros(k, q_limb); - mpn_rshift(rp, rp, rrsize, BITS_PER_MP_LIMB - k); - rp[rrsize - 1] |= (q_limb << k); + mpn_rshift(rp, rp, rrsize, BITS_PER_MP_LIMB - k); + rp[rrsize - 1] |= (q_limb << k); rexp += BITS_PER_MP_LIMB - k; } else @@ -168,55 +209,72 @@ mpfr_div (mpfr_ptr r, mpfr_srcptr u, mpfr_srcptr v, unsigned char rnd_mode) } can_round = (mpfr_can_round_raw(rp, rrsize, sign_quotient, err, - GMP_RNDN, rnd_mode, PREC(r)) + GMP_RNDN, rnd_mode, MPFR_PREC(r)) || (usize == rsize && vsize == rsize && mpfr_can_round_raw(rp, rrsize, sign_quotient, err, - GMP_RNDZ, rnd_mode, PREC(r)))); + GMP_RNDZ, rnd_mode, MPFR_PREC(r)))); /* If we used all the limbs of both the dividend and the divisor, then we have the correct RNDZ rounding */ if (!can_round && (rsize < usize || rsize < vsize)) - { + { #ifdef DEBUG - printf("Increasing the precision.\n"); + printf("Increasing the precision.\n"); #endif - printf("#"); - TMP_FREE(marker); + TMP_FREE(marker); + /* in case we can't round at the first iteration, + jump right away to the maximum precision of both + operands, to avoid multiple iterations when for + example the divisor is 1.0. + */ + if (rsize < usize) rsize = usize - 1; + if (rsize < vsize) rsize = vsize - 1; } } while (!can_round && (rsize < usize || rsize < vsize) - && (rsize++) && (rrsize++)); + && (rsize++) && (rrsize++)); /* ON PEUT PROBABLEMENT SE DEBROUILLER DES QUE rsize >= vsize */ /* MAIS IL FAUT AJOUTER LE BOUT QUI MANQUE DE usize A rsize */ + oldrrsize = rrsize; + rrsize = (MPFR_PREC(r) - 1)/BITS_PER_MP_LIMB + 1; + if (can_round) { cc = mpfr_round_raw(rp, rp, err, (sign_quotient == -1 ? 1 : 0), - PREC(r), rnd_mode); - rrsize = (PREC(r) - 1)/BITS_PER_MP_LIMB + 1; + MPFR_PREC(r), rnd_mode); } - else + else { /* Use the remainder to find out the correct rounding */ /* Note that at this point the division has been done */ /* EXACTLY. */ if ((rnd_mode == GMP_RNDD && sign_quotient == -1) || (rnd_mode == GMP_RNDU && sign_quotient == 1) || (rnd_mode == GMP_RNDN)) - { + { /* We cannot round, so that the last bits of the quotient have to be zero; just look if the remainder is nonzero */ k = rsize - 1; while (k >= 0) { if (tp[k]) break; k--; } if (k >= 0) - cc = mpn_add_1(rp, rp, rrsize, (mp_limb_t)1 << (BITS_PER_MP_LIMB - - (PREC(r) & - (BITS_PER_MP_LIMB - 1)))); + { + t = MPFR_PREC(r) & (BITS_PER_MP_LIMB - 1); + if (t) + { + cc = mpn_add_1(rp, rp, rrsize, + (mp_limb_t)1 << (BITS_PER_MP_LIMB - t)); + } + else + { + cc = mpn_add_1(rp, rp, rrsize, 1); + } + } else if (rnd_mode == GMP_RNDN) /* even rounding */ { - rw = (PREC(r) + 1) & (BITS_PER_MP_LIMB - 1); + rw = (MPFR_PREC(r) + 1) & (BITS_PER_MP_LIMB - 1); if (rw) { rw = BITS_PER_MP_LIMB - rw; nw = 0; } else nw = 1; if ((rw ? (rp[nw] >> (rw + 1)) & 1 : (rp[nw] >> (BITS_PER_MP_LIMB - 1)) & 1)) @@ -227,21 +285,26 @@ mpfr_div (mpfr_ptr r, mpfr_srcptr u, mpfr_srcptr v, unsigned char rnd_mode) } /* cas 0111111 */ } + /* Warning: we computed the result on oldrrsize limbs, but we want it + on rrsize limbs only. Both can differ, especially when the target + precision is a multiple of the number of bits per limb, since we've + taken an extra bit to make rounding to nearest easier. */ + rp += oldrrsize-rrsize; + } + + + if (sign_quotient * MPFR_SIGN(r) < 0) { MPFR_CHANGE_SIGN(r); } + MPFR_EXP(r) = rexp; - if (sign_quotient != SIGN(r)) { CHANGE_SIGN(r); } - r->_mp_exp = rexp; - if (cc) { mpn_rshift(rp, rp, rrsize, 1); rp[rrsize-1] |= (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); - r->_mp_exp++; + MPFR_EXP(r)++; } - rsize = rrsize; - rrsize = (PREC(r) - 1)/BITS_PER_MP_LIMB + 1; - MPN_COPY(r->_mp_d, rp + rsize - rrsize, rrsize); - MANT(r) [0] &= ~(((mp_limb_t)1 << (BITS_PER_MP_LIMB - - (PREC(r) & (BITS_PER_MP_LIMB - 1)))) - 1) ; - + rw = rrsize * BITS_PER_MP_LIMB - MPFR_PREC(r); + MPN_COPY(MPFR_MANT(r), rp, rrsize); + MPFR_MANT(r)[0] &= ~(((mp_limb_t)1 << rw) - 1); + TMP_FREE (marker); } diff --git a/mpfr/div_2exp.c b/mpfr/div_2exp.c index e7602db44..e518f6518 100644 --- a/mpfr/div_2exp.c +++ b/mpfr/div_2exp.c @@ -1,6 +1,6 @@ /* mpfr_div_2exp -- divide a floating-point number by a power of two -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -23,21 +23,22 @@ MA 02111-1307, USA. */ #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" void #if __STDC__ -mpfr_div_2exp(mpfr_ptr y, mpfr_srcptr x, unsigned long int n, unsigned char rnd_mode) +mpfr_div_2exp (mpfr_ptr y, mpfr_srcptr x, unsigned long int n, mp_rnd_t rnd_mode) #else -mpfr_div_2exp(y, x, n, rnd_mode) +mpfr_div_2exp (y, x, n, rnd_mode) mpfr_ptr y; - mpfr_srcptr x; - unsigned long int n; - unsigned char rnd_mode; + mpfr_srcptr x; + unsigned long int n; + mp_rnd_t rnd_mode; #endif { /* Important particular case */ if (y != x) mpfr_set(y, x, rnd_mode); - EXP(y) -= n; + MPFR_EXP(y) -= n; return; } diff --git a/mpfr/div_ui.c b/mpfr/div_ui.c index 7cd124142..bf5e94c05 100644 --- a/mpfr/div_ui.c +++ b/mpfr/div_ui.c @@ -1,6 +1,6 @@ /* mpfr_div_ui -- divide a floating-point number by a machine integer -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -22,37 +22,60 @@ MA 02111-1307, USA. */ #include <stdio.h> #include "gmp.h" #include "gmp-impl.h" -#include "longlong.h" +#include "longlong.h" #include "mpfr.h" +#include "mpfr-impl.h" /* #define DEBUG */ /* returns 0 if result exact, non-zero otherwise */ int #ifdef __STDC__ -mpfr_div_ui(mpfr_ptr y, mpfr_srcptr x, unsigned long u, unsigned char rnd_mode) +mpfr_div_ui(mpfr_ptr y, mpfr_srcptr x, unsigned long int u, mp_rnd_t rnd_mode) #else mpfr_div_ui(y, x, u, rnd_mode) - mpfr_ptr y; + mpfr_ptr y; mpfr_srcptr x; - unsigned long u; - unsigned char rnd_mode; + unsigned long int u; + mp_rnd_t rnd_mode; #endif { int xn, yn, dif, sh, i; mp_limb_t *xp, *yp, *tmp, c, d; TMP_DECL(marker); - if (FLAG_NAN(x)) { SET_NAN(y); return 1; } - if (u==0) { printf("infinity\n"); return 1; } + if (MPFR_IS_NAN(x)) { MPFR_SET_NAN(y); return 1; } + + MPFR_CLEAR_NAN(y); /* clear NaN flag */ + + if (MPFR_IS_INF(x)) + { + MPFR_SET_INF(y); + if (MPFR_SIGN(y) * MPFR_SIGN(x) < 0) /* consider u=0 as +0 */ + MPFR_CHANGE_SIGN(y); + return 0; + /* TODO: semantique de la division par un zero entier ? signe ? */ + } + + if (u==0) + { + if (MPFR_IS_ZERO(x)) { MPFR_SET_NAN(y) ; return 1; } + else + { + MPFR_SET_INF(y); MPFR_SET_SAME_SIGN(y, x); return 0; + /* TODO: semantique de la division dans ce cas-la aussi ? */ + } + } + + MPFR_CLEAR_INF(y); TMP_MARK(marker); - xn = (PREC(x)-1)/BITS_PER_MP_LIMB + 1; - yn = (PREC(y)-1)/BITS_PER_MP_LIMB + 1; + xn = (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB + 1; + yn = (MPFR_PREC(y)-1)/BITS_PER_MP_LIMB + 1; - xp = MANT(x); - yp = MANT(y); - EXP(y) = EXP(x); - if (SIGN(x)!=SIGN(y)) CHANGE_SIGN(y); + xp = MPFR_MANT(x); + yp = MPFR_MANT(y); + MPFR_EXP(y) = MPFR_EXP(x); + if (MPFR_SIGN(x) * MPFR_SIGN(y) < 0) MPFR_CHANGE_SIGN(y); dif = yn+1-xn; #ifdef DEBUG @@ -61,36 +84,36 @@ mpfr_div_ui(y, x, u, rnd_mode) #endif /* we need to store yn+1 = xn + dif limbs of the quotient */ - if (ABSSIZE(y)>=yn+1) tmp=yp; - else tmp=TMP_ALLOC((yn+1)*BYTES_PER_MP_LIMB); + /* don't use tmp=yp since the mpn_lshift call below requires yp >= tmp+1 */ + tmp=TMP_ALLOC((yn+1)*BYTES_PER_MP_LIMB); c = (mp_limb_t) u; if (dif>=0) { - /* patch for bug in mpn_divrem_1 */ -#if (UDIV_NEEDS_NORMALIZATION==1) +#if (__GNU_MP_VERSION < 3) && (UDIV_NEEDS_NORMALIZATION==1) + /* patch for bug in mpn_divrem_1 for GMP 2.xxx */ count_leading_zeros(sh, c); c <<= sh; - EXP(y) += sh; + MPFR_EXP(y) += sh; #endif c = mpn_divrem_1(tmp, dif, xp, xn, c); } else /* dif < 0 i.e. xn > yn */ c = mpn_divrem_1(tmp, 0, xp-dif, yn, c); - if (tmp[yn]==0) { tmp--; sh=0; EXP(y) -= mp_bits_per_limb; } + if (tmp[yn]==0) { tmp--; sh=0; MPFR_EXP(y) -= BITS_PER_MP_LIMB; } /* shift left to normalize */ count_leading_zeros(sh, tmp[yn]); if (sh) { mpn_lshift(yp, tmp+1, yn, sh); yp[0] += tmp[0] >> (BITS_PER_MP_LIMB-sh); - EXP(y) -= sh; + MPFR_EXP(y) -= sh; } else MPN_COPY(yp, tmp+1, yn); #ifdef DEBUG -printf("y="); mpfr_print_raw(y); putchar('\n'); + printf("y="); mpfr_print_raw(y); putchar('\n'); #endif - sh = yn*BITS_PER_MP_LIMB - PREC(y); + sh = yn*BITS_PER_MP_LIMB - MPFR_PREC(y); /* it remains sh bits in less significant limb of y */ d = *yp & (((mp_limb_t)1 << sh) - 1); @@ -106,10 +129,10 @@ printf("y="); mpfr_print_raw(y); putchar('\n'); case GMP_RNDZ: return 1; /* result is inexact */ case GMP_RNDU: - if (SIGN(y)>0) mpfr_add_one_ulp(y); + if (MPFR_SIGN(y)>0) mpfr_add_one_ulp(y); return 1; /* result is inexact */ case GMP_RNDD: - if (SIGN(y)<0) mpfr_add_one_ulp(y); + if (MPFR_SIGN(y)<0) mpfr_add_one_ulp(y); return 1; /* result is inexact */ case GMP_RNDN: if (d < ((mp_limb_t)1 << (sh-1))) return 1; diff --git a/mpfr/dump.c b/mpfr/dump.c new file mode 100644 index 000000000..a0319c015 --- /dev/null +++ b/mpfr/dump.c @@ -0,0 +1,63 @@ +/* mpfr_dump -- Dump a float to stdout. + + THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE. IT IS NOT SAFE TO + CALL THIS FUNCTION DIRECTLY. IN FACT, IT IS ALMOST GUARANTEED THAT THIS + FUNCTION WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE. + + +Copyright (C) 1993, 1994, 1995, 2000 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the GNU MP Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <strings.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +void +#if __STDC__ +mpfr_dump (mpfr_srcptr u, mp_rnd_t rnd_mode) +#else +mpfr_dump (u, rnd_mode) + mpfr_srcptr u; + mp_rnd_t rnd_mode; +#endif +{ + mp_exp_t exp; + char *str; + + if (MPFR_IS_INF(u)) + { + if (MPFR_SIGN(u) == 1) printf("Inf\n"); else printf("-Inf\n"); + return; + } + if (MPFR_IS_NAN(u)) + { + printf("NaN\n"); + return; + } + + str = mpfr_get_str (NULL, &exp, 10, 0, u, rnd_mode); + if (str[0] == '-') + printf ("-0.%se%ld\n", str + 1, exp); + else + printf ("0.%se%ld\n", str, exp); + (*_mp_free_func) (str, strlen(str)+1); +} diff --git a/mpfr/eq.c b/mpfr/eq.c new file mode 100644 index 000000000..95b04a986 --- /dev/null +++ b/mpfr/eq.c @@ -0,0 +1,135 @@ +/* mpfr_eq -- Compare two floats up to a specified bit #. + +Copied from mpf_eq. + +Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the GNU MP Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +int +#if __STDC__ +mpfr_eq (mpfr_srcptr u, mpfr_srcptr v, unsigned long int n_bits) +#else +mpfr_eq (u, v, n_bits) + mpfr_srcptr u; + mpfr_srcptr v; + unsigned long int n_bits; +#endif +{ + mp_srcptr up, vp; + mp_size_t usize, vsize, size, i; + mp_exp_t uexp, vexp; + int usign, k; + + uexp = MPFR_EXP(u); + vexp = MPFR_EXP(v); + + usize = (MPFR_PREC(u)-1)/BITS_PER_MP_LIMB + 1; + vsize = (MPFR_PREC(v)-1)/BITS_PER_MP_LIMB + 1; + + usign = MPFR_SIGN(u); + + /* 1. Are the signs different? */ + if (usign == MPFR_SIGN(v)) + { + /* U and V are both non-negative or both negative. */ + if (!MPFR_NOTZERO(u)) + return !MPFR_NOTZERO(v); + if (!MPFR_NOTZERO(v)) + return !MPFR_NOTZERO(u); + + /* Fall out. */ + } + else + { + /* Either U or V is negative, but not both. */ + if (MPFR_NOTZERO(u) || MPFR_NOTZERO(v)) + return 0; + else return 1; /* particular case -0 = +0 */ + } + + /* U and V have the same sign and are both non-zero. */ + if (MPFR_IS_INF(u)) + return (MPFR_IS_INF(v) && (usign == MPFR_SIGN(v))); + else if (MPFR_IS_INF(v)) return 0; + + if (MPFR_IS_NAN(u) || MPFR_IS_NAN(v)) return 0; + + /* 2. Are the exponents different? */ + if (uexp > vexp) + return 0; /* ??? handle (uexp = vexp + 1) */ + if (vexp > uexp) + return 0; /* ??? handle (vexp = uexp + 1) */ + + usize = ABS (usize); + vsize = ABS (vsize); + + up = MPFR_MANT(u); + vp = MPFR_MANT(v); + + if (usize > vsize) + { + if (vsize * BITS_PER_MP_LIMB < n_bits) + { + k = usize - vsize - 1; + while (k >= 0 && !up[k]) --k; + if (k >= 0) + return 0; /* surely too different */ + } + size = vsize; + } + else if (vsize > usize) + { + if (usize * BITS_PER_MP_LIMB < n_bits) + { + k = vsize - usize - 1; + while (k >= 0 && !vp[k]) --k; + if (k >= 0) + return 0; /* surely too different */ + } + size = usize; + } + else + { + size = usize; + } + + if (size > (n_bits + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB) + size = (n_bits + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB; + + up += usize - size; + vp += vsize - size; + + for (i = size - 1; i > 0; i--) + { + if (up[i] != vp[i]) + return 0; + } + + if (n_bits & (BITS_PER_MP_LIMB - 1)) + return (up[i] >> (BITS_PER_MP_LIMB - (n_bits & (BITS_PER_MP_LIMB - 1))) == + vp[i] >> (BITS_PER_MP_LIMB - (n_bits & (BITS_PER_MP_LIMB - 1)))); + else + return (up[i] == vp[i]); +} diff --git a/mpfr/exp.c b/mpfr/exp.c index c3ec218a0..4dfb614c3 100644 --- a/mpfr/exp.c +++ b/mpfr/exp.c @@ -1,6 +1,6 @@ /* mpfr_exp -- exponential of a floating-point number -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -20,14 +20,16 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <stdio.h> -#include <math.h> #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" /* #define DEBUG */ -#define LOG2 0.69314718055994528622 /* log(2) rounded to zero on 53 bits */ +extern int mpfr_exp2 _PROTO((mpfr_ptr, mpfr_srcptr, mp_rnd_t)); +extern int mpfr_exp3 _PROTO((mpfr_ptr, mpfr_srcptr, mp_rnd_t)); + /* use Brent's formula exp(x) = (1+r+r^2/2!+r^3/3!+...)^(2^K)*2^n where x = n*log(2)+(2^K)*r @@ -35,142 +37,58 @@ MA 02111-1307, USA. */ */ int #if __STDC__ -mpfr_exp(mpfr_ptr y, mpfr_srcptr x, unsigned char rnd_mode) +mpfr_exp (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode) #else -mpfr_exp(y, x, rnd_mode) - mpfr_ptr y; - mpfr_srcptr x; - unsigned char rnd_mode; +mpfr_exp (y, x, rnd_mode) + mpfr_ptr y; + mpfr_srcptr x; + mp_rnd_t rnd_mode; #endif { - int n, expx, K, precy, q, k, l, expr, err; - mpfr_t r, s, t; - - if (FLAG_NAN(x)) { SET_NAN(y); return 1; } - if (!NOTZERO(x)) { mpfr_set_ui(y, 1, GMP_RNDN); return 0; } - - expx = EXP(x); - precy = PREC(y); -#ifdef DEBUG - printf("EXP(x)=%d\n",expx); -#endif + int expx, precy; + + if (MPFR_IS_NAN(x)) { MPFR_SET_NAN(y); return 1; } + + MPFR_CLEAR_NAN(y); + + if (MPFR_IS_INF(x)) + { + if (MPFR_SIGN(x) > 0) { + MPFR_SET_INF(y); + if (MPFR_SIGN(y) < 0) MPFR_CHANGE_SIGN(y); + } + else { + MPFR_CLEAR_INF(y); + MPFR_SET_ZERO(y); + if (MPFR_SIGN(y) < 0) MPFR_CHANGE_SIGN(y); + } + /* TODO: conflits entre infinis et zeros ? */ + return 1; + } + + MPFR_CLEAR_INF(y); + + if (!MPFR_NOTZERO(x)) { mpfr_set_ui(y, 1, GMP_RNDN); return 0; } + + expx = MPFR_EXP(x); + precy = MPFR_PREC(y); /* if x > (2^31-1)*ln(2), then exp(x) > 2^(2^31-1) i.e. gives +infinity */ if (expx > 30) { - if (SIGN(x)>0) { printf("+infinity"); return 1; } - else { SET_ZERO(y); return 1; } + if (MPFR_SIGN(x)>0) { printf("+infinity"); return 1; } + else { MPFR_SET_ZERO(y); return 1; } } /* if x < 2^(-precy), then exp(x) i.e. gives 1 +/- 1 ulp(1) */ - if (expx < -precy) { int signx = SIGN(x); + if (expx < -precy) { int signx = MPFR_SIGN(x); mpfr_set_ui(y, 1, rnd_mode); if (signx>0 && rnd_mode==GMP_RNDU) mpfr_add_one_ulp(y); else if (signx<0 && (rnd_mode==GMP_RNDD || rnd_mode==GMP_RNDZ)) mpfr_sub_one_ulp(y); return 1; } - n = (int) floor(mpfr_get_d(x)/LOG2); - - K = (int) sqrt( (double) precy ); - l = (precy-1)/K + 1; - err = K + (int) ceil(log(2.0*(double)l+18.0)/LOG2); - /* add K extra bits, i.e. failure probability <= 1/2^K = O(1/precy) */ - q = precy + err + K + 3; - mpfr_init2(r, q); mpfr_init2(s, q); mpfr_init2(t, q); - /* the algorithm consists in computing an upper bound of exp(x) using - a precision of q bits, and see if we can round to PREC(y) taking - into account the maximal error. Otherwise we increase q. */ - do { -#ifdef DEBUG - printf("n=%d K=%d l=%d q=%d\n",n,K,l,q); -#endif - - /* if n<0, we have to get an upper bound of log(2) - in order to get an upper bound of r = x-n*log(2) */ - mpfr_log2(s, (n>=0) ? GMP_RNDZ : GMP_RNDU); -#ifdef DEBUG - printf("n=%d log(2)=",n); mpfr_print_raw(s); putchar('\n'); -#endif - mpfr_mul_ui(r, s, (n<0) ? -n : n, (n>=0) ? GMP_RNDZ : GMP_RNDU); - if (n<0) mpfr_neg(r, r, GMP_RNDD); - /* r = floor(n*log(2)) */ - -#ifdef DEBUG - printf("x=%1.20e\n",mpfr_get_d(x)); - printf(" ="); mpfr_print_raw(x); putchar('\n'); - printf("r=%1.20e\n",mpfr_get_d(r)); - printf(" ="); mpfr_print_raw(r); putchar('\n'); -#endif - mpfr_sub(r, x, r, GMP_RNDU); - if (SIGN(r)<0) { /* initial approximation n was too large */ - n--; - mpfr_mul_ui(r, s, (n<0) ? -n : n, GMP_RNDZ); - if (n<0) mpfr_neg(r, r, GMP_RNDD); - mpfr_sub(r, x, r, GMP_RNDU); - } -#ifdef DEBUG - printf("x-r=%1.20e\n",mpfr_get_d(r)); - printf(" ="); mpfr_print_raw(r); putchar('\n'); - if (SIGN(r)<0) { fprintf(stderr,"Error in mpfr_exp: r<0\n"); exit(1); } -#endif - mpfr_div_2exp(r, r, K, GMP_RNDU); /* r = (x-n*log(2))/2^K */ - mpfr_set_ui(s, 1, GMP_RNDU); - mpfr_set_ui(t, 1, GMP_RNDU); - - l = 1; expr = EXP(r); - do { - mpfr_mul(t, t, r, GMP_RNDU); - mpfr_div_ui(t, t, l, GMP_RNDU); - mpfr_add(s, s, t, GMP_RNDU); -#ifdef DEBUG - printf("l=%d t=%1.20e\n",l,mpfr_get_d(t)); - printf("s=%1.20e\n",mpfr_get_d(s)); -#endif - l++; - } while (EXP(t)+expr > -q); -#ifdef DEBUG - printf("l=%d q=%d (K+l)*q^2=%1.3e\n", l, q, (K+l)*(double)q*q); -#endif - - /* add 2 ulp to take into account rest of summation */ - mpfr_add_one_ulp(s); - mpfr_add_one_ulp(s); - - for (k=0;k<K;k++) { - mpfr_mul(s, s, s, GMP_RNDU); -#ifdef DEBUG - printf("k=%d s=%1.20e\n",k,mpfr_get_d(s)); -#endif - } - - if (n>0) mpfr_mul_2exp(s, s, n, GMP_RNDU); - else mpfr_div_2exp(s, s, -n, GMP_RNDU); - - /* error is at most 2^K*(2l+18) ulp */ - l = 2*l+17; k=0; while (l) { k++; l >>= 1; } - /* now k = ceil(log(2l+18)/log(2)) */ - K += k; -#ifdef DEBUG - printf("after mult. by 2^n:\n"); - if (EXP(s)>-1024) printf("s=%1.20e\n",mpfr_get_d(s)); - printf(" ="); mpfr_print_raw(s); putchar('\n'); - printf("err=%d bits\n", K); -#endif - - l = mpfr_can_round(s, q-K, GMP_RNDU, rnd_mode, precy); - if (l==0) { -#ifdef DEBUG - printf("not enough precision, use %d\n", q+BITS_PER_MP_LIMB); - printf("q=%d q-K=%d precy=%d\n",q,q-K,precy); -#endif - q += BITS_PER_MP_LIMB; - mpfr_set_prec(r, q); mpfr_set_prec(s, q); mpfr_set_prec(t, q); - } - } while (l==0); - - mpfr_set(y, s, rnd_mode); - - mpfr_clear(r); mpfr_clear(s); mpfr_clear(t); + if (precy > 13000) mpfr_exp3(y, x, rnd_mode); /* O(M(n) log(n)^2) */ + else mpfr_exp2(y, x, rnd_mode); /* O(n^(1/3) M(n)) */ return 1; } diff --git a/mpfr/exp2.c b/mpfr/exp2.c new file mode 100644 index 000000000..d18926dc4 --- /dev/null +++ b/mpfr/exp2.c @@ -0,0 +1,431 @@ +/* mpfr_exp2 -- exponential of a floating-point number + using Brent's algorithms in O(n^(1/2)*M(n)) and O(n^(1/3)*M(n)) + +Copyright (C) 1999-2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +int mpfr_exp2_aux (mpz_t, mpfr_srcptr, int, int*); +int mpfr_exp2_aux2 (mpz_t, mpfr_srcptr, int, int*); +mp_exp_t mpz_normalize (mpz_t, mpz_t, int); +int mpz_normalize2 (mpz_t, mpz_t, int, int); +int mpfr_exp2 (mpfr_ptr, mpfr_srcptr, mp_rnd_t); + +/* returns floor(sqrt(n)) */ +unsigned long _mpfr_isqrt (unsigned long n) +{ + unsigned long s; + + s = 1; + do { + s = (s + n / s) / 2; + } while (!(s*s <= n && n <= s*(s+2))); + return s; +} + +/* returns floor(n^(1/3)) */ +unsigned long _mpfr_cuberoot (unsigned long n) +{ + double s, is; + + s = 1.0; + do { + s = (2*s*s*s + (double) n) / (3*s*s); + is = (double) ((int) s); + } while (!(is*is*is <= (double) n && (double) n < (is+1)*(is+1)*(is+1))); + return (unsigned long) is; +} + +#define SWITCH 100 /* number of bits to switch from O(n^(1/2)*M(n)) method + to O(n^(1/3)*M(n)) method */ + +#define MY_INIT_MPZ(x, s) { \ + (x)->_mp_alloc = (s); \ + PTR(x) = (mp_ptr) TMP_ALLOC((s)*BYTES_PER_MP_LIMB); \ + (x)->_mp_size = 0; } + +/* #define DEBUG */ + +/* if k = the number of bits of z > q, divides z by 2^(k-q) and returns k-q. + Otherwise do nothing and return 0. + */ +mp_exp_t +#if __STDC__ +mpz_normalize (mpz_t rop, mpz_t z, int q) +#else +mpz_normalize (rop, z, q) + mpz_t rop; + mpz_t z; + int q; +#endif +{ + int k; + + k = mpz_sizeinbase(z, 2); + if (k > q) { + mpz_div_2exp(rop, z, k-q); + return k-q; + } + else { + if (rop != z) mpz_set(rop, z); + return 0; + } +} + +/* if expz > target, shift z by (expz-target) bits to the left. + if expz < target, shift z by (target-expz) bits to the right. + Returns target. +*/ +int +#if __STDC__ +mpz_normalize2 (mpz_t rop, mpz_t z, int expz, int target) +#else +mpz_normalize2 (rop, z, expz, target) + mpz_t rop; + mpz_t z; + int expz; + int target; +#endif +{ + if (target > expz) mpz_div_2exp(rop, z, target-expz); + else mpz_mul_2exp(rop, z, expz-target); + return target; +} + +/* use Brent's formula exp(x) = (1+r+r^2/2!+r^3/3!+...)^(2^K)*2^n + where x = n*log(2)+(2^K)*r + together with Brent-Kung O(t^(1/2)) algorithm for the evaluation of + power series. The resulting complexity is O(n^(1/3)*M(n)). +*/ +int +#if __STDC__ +mpfr_exp2 (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode) +#else +mpfr_exp2 (y, x, rnd_mode) + mpfr_ptr y; + mpfr_srcptr x; + mp_rnd_t rnd_mode; +#endif +{ + int n, expx, K, precy, q, k, l, err, exps; + mpfr_t r, s, t; mpz_t ss; + TMP_DECL(marker); + + if (MPFR_IS_NAN(x)) { MPFR_SET_NAN(y); return 1; } + if (MPFR_IS_INF(x)) + { + if (MPFR_SIGN(x) > 0) + { MPFR_SET_INF(y); if (MPFR_SIGN(y) == -1) { MPFR_CHANGE_SIGN(y); } } + else + { MPFR_SET_ZERO(y); if (MPFR_SIGN(y) == -1) { MPFR_CHANGE_SIGN(y); } } + /* TODO: conflits entre infinis et zeros ? */ + } + if (!MPFR_NOTZERO(x)) { mpfr_set_ui(y, 1, GMP_RNDN); return 0; } + + expx = MPFR_EXP(x); + precy = MPFR_PREC(y); +#ifdef DEBUG + printf("MPFR_EXP(x)=%d\n",expx); +#endif + + /* if x > (2^31-1)*ln(2), then exp(x) > 2^(2^31-1) i.e. gives +infinity */ + if (expx > 30) { + if (MPFR_SIGN(x) > 0) { + MPFR_SET_INF(y); + if (MPFR_SIGN(y) < 0) MPFR_CHANGE_SIGN(y); + return 1; + } + else { MPFR_SET_ZERO(y); return 1; } + } + + /* if x < 2^(-precy), then exp(x) i.e. gives 1 +/- 1 ulp(1) */ + if (expx < -precy) { int signx = MPFR_SIGN(x); + mpfr_set_ui(y, 1, rnd_mode); + if (signx>0 && rnd_mode==GMP_RNDU) mpfr_add_one_ulp(y); + else if (signx<0 && (rnd_mode==GMP_RNDD || rnd_mode==GMP_RNDZ)) + mpfr_sub_one_ulp(y); + return 1; } + + n = (int) (mpfr_get_d(x) / LOG2); + + /* for the O(n^(1/2)*M(n)) method, the Taylor series computation of + n/K terms costs about n/(2K) multiplications when computed in fixed + point */ + K = (precy<SWITCH) ? _mpfr_isqrt((precy + 1) / 2) : _mpfr_cuberoot (4*precy); + l = (precy-1)/K + 1; + err = K + (int) _mpfr_ceil_log2 (2.0 * (double) l + 18.0); + /* add K extra bits, i.e. failure probability <= 1/2^K = O(1/precy) */ + q = precy + err + K + 3; + mpfr_init2(r, q); mpfr_init2(s, q); mpfr_init2(t, q); + /* the algorithm consists in computing an upper bound of exp(x) using + a precision of q bits, and see if we can round to MPFR_PREC(y) taking + into account the maximal error. Otherwise we increase q. */ + do { +#ifdef DEBUG + printf("n=%d K=%d l=%d q=%d\n",n,K,l,q); +#endif + + /* if n<0, we have to get an upper bound of log(2) + in order to get an upper bound of r = x-n*log(2) */ + mpfr_const_log2 (s, (n>=0) ? GMP_RNDZ : GMP_RNDU); +#ifdef DEBUG + printf("n=%d log(2)=",n); mpfr_print_raw(s); putchar('\n'); +#endif + mpfr_mul_ui(r, s, (n<0) ? -n : n, (n>=0) ? GMP_RNDZ : GMP_RNDU); + if (n<0) mpfr_neg(r, r, GMP_RNDD); + /* r = floor(n*log(2)) */ + +#ifdef DEBUG + printf("x=%1.20e\n",mpfr_get_d(x)); + printf(" ="); mpfr_print_raw(x); putchar('\n'); + printf("r=%1.20e\n",mpfr_get_d(r)); + printf(" ="); mpfr_print_raw(r); putchar('\n'); +#endif + mpfr_sub(r, x, r, GMP_RNDU); + if (MPFR_SIGN(r)<0) { /* initial approximation n was too large */ + n--; + mpfr_mul_ui(r, s, (n<0) ? -n : n, GMP_RNDZ); + if (n<0) mpfr_neg(r, r, GMP_RNDD); + mpfr_sub(r, x, r, GMP_RNDU); + } +#ifdef DEBUG + printf("x-r=%1.20e\n",mpfr_get_d(r)); + printf(" ="); mpfr_print_raw(r); putchar('\n'); + if (MPFR_SIGN(r)<0) { fprintf(stderr,"Error in mpfr_exp: r<0\n"); exit(1); } +#endif + mpfr_div_2exp(r, r, K, GMP_RNDU); /* r = (x-n*log(2))/2^K */ + + TMP_MARK(marker); + MY_INIT_MPZ(ss, 3 + 2*((q-1)/BITS_PER_MP_LIMB)); + exps = mpz_set_fr(ss, s); + /* s <- 1 + r/1! + r^2/2! + ... + r^l/l! */ + l = (precy<SWITCH) ? mpfr_exp2_aux(ss, r, q, &exps) /* naive method */ + : mpfr_exp2_aux2(ss, r, q, &exps); /* Brent/Kung method */ + +#ifdef DEBUG + printf("l=%d q=%d (K+l)*q^2=%1.3e\n", l, q, (K+l)*(double)q*q); +#endif + + for (k=0;k<K;k++) { + mpz_mul(ss, ss, ss); exps <<= 1; + exps += mpz_normalize(ss, ss, q); + } + mpfr_set_z(s, ss, GMP_RNDN); MPFR_EXP(s) += exps; + + if (n>0) mpfr_mul_2exp(s, s, n, GMP_RNDU); + else mpfr_div_2exp(s, s, -n, GMP_RNDU); + + /* error is at most 2^K*(3l*(l+1)) ulp for mpfr_exp2_aux */ + if (precy<SWITCH) l = 3*l*(l+1); + else l = l*(l+4); + k=0; while (l) { k++; l >>= 1; } + /* now k = ceil(log(error in ulps)/log(2)) */ + K += k; +#ifdef DEBUG + printf("after mult. by 2^n:\n"); + if (MPFR_EXP(s)>-1024) printf("s=%1.20e\n",mpfr_get_d(s)); + printf(" ="); mpfr_print_raw(s); putchar('\n'); + printf("err=%d bits\n", K); +#endif + + l = mpfr_can_round(s, q-K, GMP_RNDN, rnd_mode, precy); + if (l==0) { +#ifdef DEBUG + printf("not enough precision, use %d\n", q+BITS_PER_MP_LIMB); + printf("q=%d q-K=%d precy=%d\n",q,q-K,precy); +#endif + q += BITS_PER_MP_LIMB; + mpfr_set_prec(r, q); mpfr_set_prec(s, q); mpfr_set_prec(t, q); + } + } while (l==0); + + mpfr_set(y, s, rnd_mode); + + TMP_FREE(marker); + mpfr_clear(r); mpfr_clear(s); mpfr_clear(t); + return 1; +} + +/* s <- 1 + r/1! + r^2/2! + ... + r^l/l! while MPFR_EXP(r^l/l!)+MPFR_EXPR(r)>-q + using naive method with O(l) multiplications. + Return the number of iterations l. + The absolute error on s is less than 3*l*(l+1)*2^(-q). + Version using fixed-point arithmetic with mpz instead + of mpfr for internal computations. + s must have at least qn+1 limbs (qn should be enough, but currently fails + since mpz_mul_2exp(s, s, q-1) reallocates qn+1 limbs) +*/ +int +#if __STDC__ +mpfr_exp2_aux(mpz_t s, mpfr_srcptr r, int q, int *exps) +#else +mpfr_exp2_aux(s, r, q, exps) + mpz_t s; + mpfr_srcptr r; + int q; + int *exps; +#endif +{ + int l, dif, qn; + mpz_t t, rr; mp_exp_t expt, expr; + TMP_DECL(marker); + + TMP_MARK(marker); + qn = 1 + (q-1)/BITS_PER_MP_LIMB; + MY_INIT_MPZ(t, 2*qn+1); /* 2*qn+1 is neeeded since mpz_div_2exp may + need an extra limb */ + MY_INIT_MPZ(rr, qn+1); + mpz_set_ui(t, 1); expt=0; + mpz_set_ui(s, 1); mpz_mul_2exp(s, s, q-1); *exps = 1-q; /* s = 2^(q-1) */ + expr = mpz_set_fr(rr, r); /* no error here */ + + l = 0; + do { + l++; + mpz_mul(t, t, rr); expt=expt+expr; + dif = *exps + mpz_sizeinbase(s, 2) - expt - mpz_sizeinbase(t, 2); + /* truncates the bits of t which are < ulp(s) = 2^(1-q) */ + expt += mpz_normalize(t, t, q-dif); /* error at most 2^(1-q) */ + mpz_div_ui(t, t, l); /* error at most 2^(1-q) */ + /* the error wrt t^l/l! is here at most 3*l*ulp(s) */ +#ifdef DEBUG + if (expt != *exps) { + fprintf(stderr, "Error: expt != exps %d %d\n", expt, *exps); exit(1); + } +#endif + mpz_add(s, s, t); /* no error here: exact */ + /* ensures rr has the same size as t: after several shifts, the error + on rr is still at most ulp(t)=ulp(s) */ + expr += mpz_normalize(rr, rr, mpz_sizeinbase(t, 2)); + } while (mpz_cmp_ui(t, 0)); + + TMP_FREE(marker); + return l; +} + +/* s <- 1 + r/1! + r^2/2! + ... + r^l/l! while MPFR_EXP(r^l/l!)+MPFR_EXPR(r)>-q + using Brent/Kung method with O(sqrt(l)) multiplications. + Return l. + Uses m multiplications of full size and 2l/m of decreasing size, + i.e. a total equivalent to about m+l/m full multiplications, + i.e. 2*sqrt(l) for m=sqrt(l). + Version using mpz. ss must have at least (sizer+1) limbs. + The error is bounded by (l^2+4*l) ulps where l is the return value. +*/ +int +#if __STDC__ +mpfr_exp2_aux2 (mpz_t s, mpfr_srcptr r, int q, int *exps) +#else +mpfr_exp2_aux2 (s, r, q, exps) + mpz_t s; + mpfr_srcptr r; + int q; + int *exps; +#endif +{ + int expr, l, m, i, sizer, *expR, expt, ql; + unsigned long int c; + mpz_t t, *R, rr, tmp; + TMP_DECL(marker); + + /* estimate value of l */ + l = q / (-MPFR_EXP(r)); + m = (int) _mpfr_isqrt (l); + /* we access R[2], thus we need m >= 2 */ + if (m < 2) m = 2; + TMP_MARK(marker); + R = (mpz_t*) TMP_ALLOC((m+1)*sizeof(mpz_t)); /* R[i] stands for r^i */ + expR = (int*) TMP_ALLOC((m+1)*sizeof(int)); /* exponent for R[i] */ + sizer = 1 + (MPFR_PREC(r)-1)/BITS_PER_MP_LIMB; + mpz_init(tmp); + MY_INIT_MPZ(rr, sizer+2); + MY_INIT_MPZ(t, 2*sizer); /* double size for products */ + mpz_set_ui(s, 0); *exps = 1-q; /* initialize s to zero, 1 ulp = 2^(1-q) */ + for (i=0;i<=m;i++) MY_INIT_MPZ(R[i], sizer+2); + expR[1] = mpz_set_fr(R[1], r); /* exact operation: no error */ + expR[1] = mpz_normalize2(R[1], R[1], expR[1], 1-q); /* error <= 1 ulp */ + mpz_mul(t, R[1], R[1]); /* err(t) <= 2 ulps */ + mpz_div_2exp(R[2], t, q-1); /* err(R[2]) <= 3 ulps */ + expR[2] = 1-q; + for (i=3;i<=m;i++) { + mpz_mul(t, R[i-1], R[1]); /* err(t) <= 2*i-2 */ + mpz_div_2exp(R[i], t, q-1); /* err(R[i]) <= 2*i-1 ulps */ + expR[i] = 1-q; + } + mpz_set_ui(R[0], 1); mpz_mul_2exp(R[0], R[0], q-1); expR[0]=1-q; /* R[0]=1 */ + mpz_set_ui(rr, 1); expr=0; /* rr contains r^l/l! */ + /* by induction: err(rr) <= 2*l ulps */ + + l = 0; + ql = q; /* precision used for current giant step */ + do { + /* all R[i] must have exponent 1-ql */ + if (l) for (i=0;i<m;i++) { + expR[i] = mpz_normalize2(R[i], R[i], expR[i], 1-ql); + } + /* the absolute error on R[i]*rr is still 2*i-1 ulps */ + expt = mpz_normalize2(t, R[m-1], expR[m-1], 1-ql); + /* err(t) <= 2*m-1 ulps */ + /* computes t = 1 + r/(l+1) + ... + r^(m-1)*l!/(l+m-1)! + using Horner's scheme */ + for (i=m-2;i>=0;i--) { + mpz_div_ui(t, t, l+i+1); /* err(t) += 1 ulp */ + mpz_add(t, t, R[i]); + } + /* now err(t) <= (3m-2) ulps */ + + /* now multiplies t by r^l/l! and adds to s */ + mpz_mul(t, t, rr); expt += expr; + expt = mpz_normalize2(t, t, expt, *exps); + /* err(t) <= (3m-1) + err_rr(l) <= (3m-2) + 2*l */ +#ifdef DEBUG + if (expt != *exps) { + fprintf(stderr, "Error: expt != exps %d %d\n", expt, *exps); exit(1); + } +#endif + mpz_add(s, s, t); /* no error here */ + + /* updates rr, the multiplication of the factors l+i could be done + using binary splitting too, but it is not sure it would save much */ + mpz_mul(t, rr, R[m]); /* err(t) <= err(rr) + 2m-1 */ + expr += expR[m]; + mpz_set_ui (tmp, 1); + for (i=1, c=1; i<=m; i++) { + if (l+i > ~((unsigned long int) 0)/c) { + mpz_mul_ui(tmp, tmp, c); + c = l+i; + } + else c *= (unsigned long int) l+i; + } + if (c != 1) mpz_mul_ui (tmp, tmp, c); /* tmp is exact */ + mpz_fdiv_q(t, t, tmp); /* err(t) <= err(rr) + 2m */ + expr += mpz_normalize(rr, t, ql); /* err_rr(l+1) <= err_rr(l) + 2m+1 */ + ql = q - *exps - mpz_sizeinbase(s, 2) + expr + mpz_sizeinbase(rr, 2); + l+=m; + } while (expr+mpz_sizeinbase(rr, 2) > -q); + + TMP_FREE(marker); + mpz_clear(tmp); + return l; +} diff --git a/mpfr/exp3.c b/mpfr/exp3.c new file mode 100644 index 000000000..42819d5d8 --- /dev/null +++ b/mpfr/exp3.c @@ -0,0 +1,250 @@ +/* mpfr_exp -- exponential of a floating-point number + +Copyright (C) 1999 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +/* #define DEBUG */ + +int mpfr_exp_rational (mpfr_ptr, mpz_srcptr, int, int); +int mpfr_exp3 (mpfr_ptr, mpfr_srcptr, mp_rnd_t); + +int +#if __STDC__ +mpfr_exp_rational (mpfr_ptr y, mpz_srcptr p, int r, int m) +#else +mpfr_exp_rational (y, p, r, m) + mpfr_ptr y; + mpz_srcptr p; + int r; + int m; +#endif +{ + int n,i,k,j,l; + mpz_t* P,*S; + mpz_t* ptoj; + int diff,expo; + int precy = MPFR_PREC(y); + int * mult; + int prec_i_have; + int *nb_terms; + int accu; + TMP_DECL (marker); + + TMP_MARK (marker); + n = 1 << m; + P = (mpz_t*) TMP_ALLOC((m+1) * sizeof(mpz_t)); + S = (mpz_t*) TMP_ALLOC((m+1) * sizeof(mpz_t)); + ptoj = (mpz_t*) TMP_ALLOC((m+1) * sizeof(mpz_t)); /* ptoj[i] = mantissa^(2^i) */ + mult = (int*) TMP_ALLOC((m+1) * sizeof(int)); + nb_terms = (int*) TMP_ALLOC((m+1) * sizeof(int)); + mult[0] = 0; + for (i=0;i<=m;i++) { mpz_init(P[i]); mpz_init(S[i]); mpz_init(ptoj[i]); } + mpz_set(ptoj[0], p); + for (i=1;i<m;i++) mpz_mul(ptoj[i], ptoj[i-1], ptoj[i-1]); + mpz_set_ui(P[0], 1); + mpz_set_ui(S[0], 1); + k = 0; + nb_terms[0] = 1; + prec_i_have = 0; + for (i=1;(prec_i_have < precy) && (i < n) ;i++) { + k++; + nb_terms[k] = 1; + mpz_set_ui(P[k], i+1); + mpz_set(S[k], P[k]);; + j=i+1; l=0; while ((j & 1) == 0) { + mpz_mul(S[k], S[k], ptoj[l]); + mpz_mul(S[k-1], S[k-1], P[k]); + mpz_mul_2exp(S[k-1], S[k-1], r*(1<<l)); + mpz_add(S[k-1], S[k-1], S[k]); + mpz_mul(P[k-1], P[k-1], P[k]); + nb_terms[k-1] = nb_terms[k-1]+ nb_terms[k]; + mult[k] = mult[k-1] + (1 << l)*(r >> 2) + mpz_sizeinbase(P[k],2) - 1; + prec_i_have = mult[k]; + l++; j>>=1; k--; + } + } + l = 0; + accu = 0; + while (k > 0){ + mpz_mul(S[k], S[k], ptoj[_mpfr_ceil_log2((double) nb_terms[k])]); + mpz_mul(S[k-1], S[k-1], P[k]); + accu += nb_terms[k]; + mpz_mul_2exp(S[k-1], S[k-1], r* accu); + mpz_add(S[k-1], S[k-1], S[k]); + mpz_mul(P[k-1], P[k-1], P[k]); + l++; k--; + } + + diff = mpz_sizeinbase(S[0],2) - 2*precy; + expo = diff; + if (diff >=0) + { + mpz_div_2exp(S[0],S[0],diff); + } else + { + mpz_mul_2exp(S[0],S[0],-diff); + } + diff = mpz_sizeinbase(P[0],2) - precy; + expo -= diff; + if (diff >=0) + { + mpz_div_2exp(P[0],P[0],diff); + } else + { + mpz_mul_2exp(P[0],P[0],-diff); + } + + mpz_tdiv_q(S[0], S[0], P[0]); + mpfr_set_z(y,S[0], GMP_RNDD); + MPFR_EXP(y) += expo; + + mpfr_div_2exp(y, y, r*(i-1),GMP_RNDN); + for (i=0;i<=m;i++) { mpz_clear(P[i]); mpz_clear(S[i]); mpz_clear(ptoj[i]); } + TMP_FREE (marker); + return 0; +} + +#define shift (BITS_PER_MP_LIMB/2) + +int +#if __STDC__ +mpfr_exp3 (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode) +#else +mpfr_exp3 (y, x, rnd_mode) + mpfr_ptr y; + mpfr_srcptr x; + mp_rnd_t rnd_mode; +#endif +{ + mpfr_t t; + mpfr_t x_copy; + int i,k; + mpz_t uk; + mpfr_t tmp; + int ttt; + int twopoweri; + int Prec; + int loop; + int prec_x; + int shift_x = 0; + int good = 0; + int realprec = 0; + int iter; + int logn; + + /* commencons par 0 */ + if (MPFR_IS_NAN(x)) { MPFR_SET_NAN(y); return 1; } + + if (MPFR_IS_INF(x)) + { + if (MPFR_SIGN(x) > 0) + { MPFR_SET_INF(y); if (MPFR_SIGN(y) == -1) { MPFR_CHANGE_SIGN(y); } } + else + { MPFR_SET_ZERO(y); if (MPFR_SIGN(y) == -1) { MPFR_CHANGE_SIGN(y); } } + /* TODO: conflits entre infinis et zeros ? */ + } + + if (!MPFR_NOTZERO(x)) { + mpfr_set_ui(y, 1, GMP_RNDN); + return 0; + } + + /* Decomposer x */ + /* on commence par ecrire x = 1.xxxxxxxxxxxxx + ----- k bits -- */ + prec_x = _mpfr_ceil_log2 ((double) (MPFR_PREC(x)) / BITS_PER_MP_LIMB); + if (prec_x < 0) prec_x = 0; + logn = _mpfr_ceil_log2 ((double) prec_x + MPFR_PREC(y)); + if (logn < 2) logn = 2; + ttt = MPFR_EXP(x); + mpfr_init2(x_copy,MPFR_PREC(x)); + mpfr_set(x_copy,x,GMP_RNDD); + /* on fait le shift pour que le nombre soit inferieur a 1 */ + if (ttt > 0) + { + shift_x = ttt; + mpfr_mul_2exp(x_copy,x,-ttt, GMP_RNDN); + ttt = MPFR_EXP(x_copy); + } + realprec = MPFR_PREC(y)+logn; + mpz_init (uk); + while (!good){ + Prec = realprec+shift+2+shift_x; + k = _mpfr_ceil_log2 ((double) Prec / BITS_PER_MP_LIMB); + + /* now we have to extract */ + mpfr_init2(t, Prec); + mpfr_init2(tmp, Prec); + mpfr_set_ui(tmp,1,GMP_RNDN); + twopoweri = BITS_PER_MP_LIMB; + if (k <= prec_x) iter = k; else iter= prec_x; + for(i = 0; i <= iter; i++){ + mpfr_extract (uk, x_copy, i); +#ifdef DEBUG + mpz_out_str(stderr,2, uk); + fprintf(stderr, "---\n"); + fprintf(stderr, "---%d\n", twopoweri - ttt); +#endif + if (i) + mpfr_exp_rational (t, uk, twopoweri - ttt, k - i + 1); + else + { + /* cas particulier : on est oblige de faire les calculs avec x/2^. + puis elever au carre (plus rapide) */ + mpfr_exp_rational (t, uk, shift + twopoweri - ttt, k+1); + for (loop= 0 ; loop < shift; loop++) + mpfr_mul(t,t,t,GMP_RNDD); + + } + mpfr_mul(tmp,tmp,t,GMP_RNDD); +#ifdef DEBUG + fprintf(stderr, "fin\n"); + mpfr_out_str(stderr, 2, MPFR_PREC(y), t, GMP_RNDD); + fprintf(stderr, "\n ii --- ii \n"); +#endif + twopoweri <<= 1; + } + for (loop= 0 ; loop < shift_x; loop++) + mpfr_mul(tmp,tmp,tmp,GMP_RNDD); + mpfr_clear(t); + if (mpfr_can_round(tmp, realprec, GMP_RNDD, rnd_mode, MPFR_PREC(y))){ + mpfr_set(y,tmp,rnd_mode); + mpfr_clear(tmp); + good = 1; + } else { + mpfr_clear(tmp); + realprec += 3*logn; + } + } + mpz_clear (uk); + mpfr_clear(x_copy); + return 0; +} + + + + + + diff --git a/mpfr/extract.c b/mpfr/extract.c new file mode 100644 index 000000000..ccfd380b7 --- /dev/null +++ b/mpfr/extract.c @@ -0,0 +1,66 @@ +/* mpfr_extract -- bit-extraction function for the binary splitting algorithm + +Copyright (C) 2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" +#include "gmp-impl.h" + + +/* given 0 <= |p| < 1, this function extracts limbs of p and puts them in y. + It is mainly designed for the "binary splitting" algorithm together with + generic.c. + + More precisely, if B = 2^BITS_PER_MP_LIMB: + - for i=0, y = floor(p * B) + - for i>0, y = (p * B^(2^i)) mod B^(2^(i-1)) + */ +void +#if __STDC__ +mpfr_extract (mpz_ptr y, mpfr_srcptr p, unsigned int i) +#else +mpfr_extract (y, p, i) + mpz_ptr y; + mpfr_srcptr p; + unsigned int i; +#endif +{ + int two_i = 1 << i; + int two_i_2 = i ? two_i / 2 : 1; + mp_size_t size_p = MPFR_ABSSIZE(p); + + /* as 0 <= |p| < 1, we don't have to care with infinities, NaN, ... */ + + _mpz_realloc (y, two_i_2); + if (size_p < two_i) { + MPN_ZERO (PTR(y), two_i_2); + if (size_p >= two_i_2) + MPN_COPY (PTR(y) + two_i - size_p, MPFR_MANT(p), size_p - two_i_2); + } + else + MPN_COPY (PTR(y), MPFR_MANT(p) + size_p - two_i, two_i_2); + + MPN_NORMALIZE (PTR(y), two_i_2); + SIZ(y) = (MPFR_ISNEG(p)) ? -two_i_2 : two_i_2; +} + + + diff --git a/mpfr/generic.c b/mpfr/generic.c new file mode 100644 index 000000000..f44e5d1c7 --- /dev/null +++ b/mpfr/generic.c @@ -0,0 +1,230 @@ +/* + +Copyright (C) 1999 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPdFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#ifndef GENERIC +# error You should specify a name +#endif + +/* TODO: Reflechir a un traitement generique des infinis ? */ + +#ifdef B +# ifndef A +# error B cannot be used without A +# endif +#endif + +/* Calcule les 2^m premiers termes de la serie hypergeometrique + avec x = p / 2^r */ +int +#if __STDC__ +GENERIC (mpfr_ptr y, mpz_srcptr p, int r, int m) +#else +GENERIC (y, p, r, m) + mpfr_ptr y; + mpz_srcptr p; + int r; + int m; +#endif +{ + int n,i,k,j,l; + int is_p_one = 0; + mpz_t* P,*S; +#ifdef A + mpz_t *T; +#endif + mpz_t* ptoj; +#ifdef R_IS_RATIONAL + mpz_t* qtoj; + mpfr_t tmp; +#endif + int diff,expo; + int precy = MPFR_PREC(y); + MPFR_CLEAR_FLAGS(y); + n = 1 << m; + P = (mpz_t*) (*_mp_allocate_func) ((m+1) * sizeof(mpz_t)); + S = (mpz_t*) (*_mp_allocate_func) ((m+1) * sizeof(mpz_t)); + ptoj = (mpz_t*) (*_mp_allocate_func) ((m+1) * sizeof(mpz_t)); /* ptoj[i] = mantissa^(2^i) */ +#ifdef A + T = (mpz_t*) (*_mp_allocate_func) ((m+1) * sizeof(mpz_t)); +#endif +#ifdef R_IS_RATIONAL + qtoj = (mpz_t*) (*_mp_allocate_func) ((m+1) * sizeof(mpz_t)); +#endif + if ((P == NULL) || (S == NULL) || (ptoj == NULL) +#ifdef A + || (T == NULL) +#endif +#ifdef R_IS_RATIONAL + || (qtoj == NULL) +#endif + ) { + fprintf (stderr, "Error in mpfr_generic: no more memory available\n"); + exit (1); + } + for (i=0;i<=m;i++) { mpz_init(P[i]); mpz_init(S[i]); mpz_init(ptoj[i]); +#ifdef R_IS_RATIONAL + mpz_init(qtoj[i]); +#endif +#ifdef A + mpz_init(T[i]); +#endif + } + mpz_set(ptoj[0], p); +#ifdef C +# if C2 != 1 + mpz_mul_ui(ptoj[0], ptoj[0], C2); +# endif +#endif + is_p_one = !mpz_cmp_si(ptoj[0], 1); +#ifdef A +# ifdef B + mpz_set_ui(T[0], A1 * B1); +# else + mpz_set_ui(T[0], A1); +# endif +#endif + if (!is_p_one) + for (i=1;i<m;i++) mpz_mul(ptoj[i], ptoj[i-1], ptoj[i-1]); +#ifdef R_IS_RATIONAL + mpz_set_si(qtoj[0], r); + for (i=1;i<=m;i++) + { + mpz_mul(qtoj[i], qtoj[i-1], qtoj[i-1]); + } +#endif + + mpz_set_ui(P[0], 1); + mpz_set_ui(S[0], 1); + k = 0; + for (i=1;(i < n) ;i++) { + k++; + +#ifdef A +# ifdef B + mpz_set_ui(T[k], (A1 + A2*i)*(B1+B2*i)); +# else + mpz_set_ui(T[k], A1 + A2*i); +# endif +#endif + +#ifdef C +# ifdef NO_FACTORIAL + mpz_set_ui(P[k], (C1 + C2 * (i-1))); + mpz_set_ui(S[k], 1); +# else + mpz_set_ui(P[k], (i+1) * (C1 + C2 * (i-1))); + mpz_set_ui(S[k], i+1); +# endif +#else +# ifdef NO_FACTORIAL + mpz_set_ui(P[k], 1); +# else + mpz_set_ui(P[k], i+1); +# endif + mpz_set(S[k], P[k]); +#endif + j=i+1; l=0; while ((j & 1) == 0) { + if (!is_p_one) + mpz_mul(S[k], S[k], ptoj[l]); +#ifdef A +# ifdef B +# if (A2*B2) != 1 + mpz_mul_ui(P[k], P[k], A2*B2); +# endif +# else +# if A2 != 1 + mpz_mul_ui(P[k], P[k], A2); +# endif +#endif + mpz_mul(S[k], S[k], T[k-1]); +#endif + mpz_mul(S[k-1], S[k-1], P[k]); +#ifdef R_IS_RATIONAL + mpz_mul(S[k-1], S[k-1], qtoj[l]); +#else + mpz_mul_2exp(S[k-1], S[k-1], r*(1<<l)); +#endif + mpz_add(S[k-1], S[k-1], S[k]); + mpz_mul(P[k-1], P[k-1], P[k]); +#ifdef A + mpz_mul(T[k-1], T[k-1], T[k]); +#endif + l++; j>>=1; k--; + } + } + + diff = mpz_sizeinbase(S[0],2) - 2*precy; + expo = diff; + if (diff >=0) + { + mpz_div_2exp(S[0],S[0],diff); + } else + { + mpz_mul_2exp(S[0],S[0],-diff); + } + diff = mpz_sizeinbase(P[0],2) - precy; + expo -= diff; + if (diff >=0) + { + mpz_div_2exp(P[0],P[0],diff); + } else + { + mpz_mul_2exp(P[0],P[0],-diff); + } + + mpz_tdiv_q(S[0], S[0], P[0]); + mpfr_set_z(y,S[0], GMP_RNDD); + MPFR_EXP(y) += expo; + +#ifdef R_IS_RATIONAL + /* division exacte */ + mpz_div_ui(qtoj[m], qtoj[m], r); + i = (MPFR_PREC(y)); + mpfr_init2(tmp,i); + mpfr_set_z(tmp, qtoj[m] , GMP_RNDD); + mpfr_div(y, y, tmp,GMP_RNDD); + mpfr_clear(tmp); +#else + mpfr_div_2exp(y, y, r*(i-1),GMP_RNDN); +#endif + for (i=0;i<=m;i++) { mpz_clear(P[i]); mpz_clear(S[i]); mpz_clear(ptoj[i]); +#ifdef R_IS_RATIONAL + mpz_clear(qtoj[i]); +#endif +#ifdef A + mpz_clear(T[i]); +#endif + } + (*_mp_free_func) (P, (m+1) * sizeof(mpz_t)); + (*_mp_free_func) (S, (m+1) * sizeof(mpz_t)); + (*_mp_free_func) (ptoj, (m+1) * sizeof(mpz_t)); +#ifdef R_IS_RATIONAL + (*_mp_free_func) (qtoj, (m+1) * sizeof(mpz_t)); +#endif +#ifdef A + (*_mp_free_func) (T, (m+1) * sizeof(mpz_t)); +#endif + return 0; +} + + + + diff --git a/mpfr/get_str.c b/mpfr/get_str.c index 7cd7d5d00..9c1391c19 100644 --- a/mpfr/get_str.c +++ b/mpfr/get_str.c @@ -1,6 +1,6 @@ /* mpfr_get_str -- output a floating-point number to a string -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -19,7 +19,8 @@ along with the MPFR Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include <math.h> +/* #define DEBUG */ + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -27,6 +28,7 @@ MA 02111-1307, USA. */ #include "gmp-impl.h" #include "longlong.h" #include "mpfr.h" +#include "mpfr-impl.h" /* Convert op to a string in base 'base' with 'n' digits and writes the @@ -37,32 +39,54 @@ MA 02111-1307, USA. */ */ #if __STDC__ char *mpfr_get_str(char *str, mp_exp_t *expptr, int base, size_t n, - mpfr_srcptr op, unsigned char rnd_mode) + mpfr_srcptr op, mp_rnd_t rnd_mode) #else char *mpfr_get_str(str, expptr, base, n, op, rnd_mode) - char *str; + char *str; mp_exp_t *expptr; int base; size_t n; - mpfr_srcptr op; - unsigned char rnd_mode; + mpfr_srcptr op; + mp_rnd_t rnd_mode; #endif { double d; long e, q, div, p, err, prec, sh; mpfr_t a, b; mpz_t bz; - char *str0; unsigned char rnd1; int f, pow2, ok=0, neg; + char *str0=NULL; mp_rnd_t rnd1; int f, pow2, ok=0, neg; if (base<2 || 36<base) { fprintf(stderr, "Error: too small or too large base in mpfr_get_str: %d\n", base); exit(1); } + + neg = (MPFR_SIGN(op)<0) ? 1 : 0; + + if (MPFR_IS_INF(op)) { + if (str == NULL) { + str = (*_mp_allocate_func)(neg + 4); + if (str == NULL) { + fprintf (stderr, "Error in mpfr_get_str: no more memory available\n"); + exit (1); + } + } + str0 = str; + if (neg) { *str++ = '-'; } + *str++ = 'I'; *str++ = 'n'; *str++ = 'f'; *str='\0'; + return str0; + } - neg = (SIGN(op)<0) ? 1 : 0; - - if (!NOTZERO(op)) { - if (str==NULL) str0=str=(*__gmp_allocate_func)(neg + n + 2); - if (SIGN(op)<0) *str++ = '-'; + if (!MPFR_NOTZERO(op)) { + if (str == NULL) { + str = (*_mp_allocate_func)(neg + n + 1); + if (str == NULL) { + fprintf (stderr, "Error in mpfr_get_str: no more memory available\n"); + exit (1); + } + } + str0 = str; + if (MPFR_SIGN(op)<0) *str++ = '-'; for (f=0;f<n;f++) *str++ = '0'; + *str++ = '\0'; *expptr = 1; return str0; } @@ -73,29 +97,41 @@ char *mpfr_get_str(str, expptr, base, n, op, rnd_mode) /* if pow2 <> 0, then base = 2^pow2 */ /* first determines the exponent */ - e = EXP(op); - d = fabs(mpfr_get_d2(op, 0)); + e = MPFR_EXP(op); + d = ABS(mpfr_get_d2(op, 0)); /* the absolute value of op is between 1/2*2^e and 2^e */ /* the output exponent f is such that base^(f-1) <= |op| < base^f i.e. f = 1 + floor(log(|op|)/log(base)) = 1 + floor((log(|m|)+e*log(2))/log(base)) */ - f = 1 + (int) floor((log(d)+(double)e*log(2.0))/log((double)base)); + /* f = 1 + (int) floor((log(d)/LOG2+(double)e)*LOG2/log((double)base)); */ + d = ((double) e + (double) _mpfr_floor_log2(d)) + * __mp_bases[base].chars_per_bit_exactly; + /* warning: (int) d rounds towards 0 */ + f = (int) d; /* f equals floor(d) if d >= 0 and ceil(d) if d < 0 */ + if (f <= d) f++; if (n==0) { - /* performs exact rounding, i.e. returns y such that for rnd_mode=RNDN - for example, we have: - y*base^(f-n) <= x*2^(e-p) < (x+1)*2^(e-p) <= (y+1)*base^(f-n) - which implies 2^(EXP(op)-PREC(op)) <= base^(f-n) + /* performs exact rounding, i.e. returns y such that for GMP_RNDU + for example, we have: x*2^(e-p) <= y*base^(f-n) */ - n = f + (int) ceil(((double)PREC(op)-e)*log(2.0)/log((double)base)); + n = (int) (__mp_bases[base].chars_per_bit_exactly * MPFR_PREC(op)); + if (n==0) n=1; } +#ifdef DEBUG + printf("f=%d n=%d MPFR_EXP(op)=%d MPFR_PREC(op)=%d\n", f, n, e, MPFR_PREC(op)); +#endif /* now the first n digits of the mantissa are obtained from rnd(op*base^(n-f)) */ - prec = (long) ceil((double)n*log((double)base)/log(2.0)); + if (pow2) prec = n*pow2; + else + prec = 1 + (long) ((double) n / __mp_bases[base].chars_per_bit_exactly); +#ifdef DEBUG + printf("prec=%d\n", prec); +#endif err = 5; q = prec+err; /* one has to use at least q bits */ q = (((q-1)/BITS_PER_MP_LIMB)+1)*BITS_PER_MP_LIMB; - mpfr_init2(a,q); mpfr_init2(b,q); + mpfr_init2(a, q); mpfr_init2(b, q); do { p = n-f; if ((div=(p<0))) p=-p; @@ -126,80 +162,66 @@ char *mpfr_get_str(str, expptr, base, n, op, rnd_mode) mpfr_div(a, b, a, rnd_mode); } /* now a is an approximation by default of 1/base^(f-n) */ +#ifdef DEBUG + printf("base^(n-f)=%1.20e\n", mpfr_get_d(a)); +#endif mpfr_mul(b, op, a, rnd_mode); } } - if (neg) CHANGE_SIGN(b); /* put b positive */ - + if (neg) MPFR_CHANGE_SIGN(b); /* put b positive */ +#ifdef DEBUG + printf("p=%d b=%1.20e\n", p, mpfr_get_d(b)); + printf("q=%d 2*prec+BITS_PER_MP_LIMB=%d\n", q, 2*prec+BITS_PER_MP_LIMB); +#endif if (q>2*prec+BITS_PER_MP_LIMB) { - /* happens when just in the middle between two digits */ - n--; q-=BITS_PER_MP_LIMB; - if (n==0) { - fprintf(stderr, "cannot determine leading digit\n"); exit(1); - } + /* if the intermediate precision exceeds twice that of the input, + a worst-case for the division cannot occur */ + ok=1; + rnd_mode=GMP_RNDN; } - ok = pow2 || mpfr_can_round(b, q-err, rnd_mode, rnd_mode, prec); + else ok = pow2 || mpfr_can_round(b, q-err, rnd_mode, rnd_mode, prec); - if (ok) { - if (pow2) { - sh = e-PREC(op) + pow2*(n-f); /* error at most 2^e */ - ok = mpfr_can_round(b, EXP(b)-sh-1, rnd_mode, rnd_mode, n*pow2); - } - else { - /* check that value is the same at distance 2^(e-PREC(op))/base^(f-n) - in opposite from rounding direction */ - if (e>=PREC(op)) mpfr_mul_2exp(a, a, e-PREC(op), rnd_mode); - else mpfr_div_2exp(a, a, PREC(op)-e, rnd_mode); - if (rnd_mode==GMP_RNDN) { - mpfr_div_2exp(a, a, 2, rnd_mode); - mpfr_sub(b, b, a, rnd_mode); /* b - a/2 */ - mpfr_mul_2exp(a, a, 2, rnd_mode); - mpfr_add(a, b, a, rnd_mode); /* b + a/2 */ - } - else if ((rnd_mode==GMP_RNDU && neg==0) || (rnd_mode==GMP_RNDD && neg)) - mpfr_sub(a, b, a, rnd_mode); - else mpfr_add(a, b, a, rnd_mode); - /* check that a and b are rounded similarly */ - prec=EXP(b); - if (EXP(a) != prec) ok=0; - else { - mpfr_round(b, rnd_mode, prec); - mpfr_round(a, rnd_mode, prec); - if (mpfr_cmp(a, b)) ok=0; - } - } - if (ok==0) { /* n is too large */ - n--; - if (n==0) { - fprintf(stderr, "cannot determine leading digit\n"); exit(1); - } - q -= BITS_PER_MP_LIMB; - } - } } while (ok==0 && (q+=BITS_PER_MP_LIMB) ); + if (neg) switch (rnd_mode) { case GMP_RNDU: rnd_mode=GMP_RNDZ; break; case GMP_RNDD: rnd_mode=GMP_RNDU; break; } - prec=EXP(b); /* may have changed due to rounding */ + if (ok) mpfr_round(b, rnd_mode, MPFR_EXP(b)); + + prec=MPFR_EXP(b); /* may have changed due to rounding */ /* now the mantissa is the integer part of b */ mpz_init(bz); q=1+(prec-1)/BITS_PER_MP_LIMB; _mpz_realloc(bz, q); sh = prec%BITS_PER_MP_LIMB; - e = 1 + (PREC(b)-1)/BITS_PER_MP_LIMB-q; - if (sh) mpn_rshift(PTR(bz), MANT(b)+e, q, BITS_PER_MP_LIMB-sh); - else MPN_COPY(PTR(bz), MANT(b)+e, q); + e = 1 + (MPFR_PREC(b)-1)/BITS_PER_MP_LIMB-q; + if (sh) mpn_rshift(PTR(bz), MPFR_MANT(b)+e, q, BITS_PER_MP_LIMB-sh); + else MPN_COPY(PTR(bz), MPFR_MANT(b)+e, q); bz->_mp_size=q; /* computes the number of characters needed */ q = neg + n + 2; /* n+1 may not be enough for 100000... */ - if (str==NULL) str0=str=(*__gmp_allocate_func)(q); + if (str == NULL) { + str0 = str = (*_mp_allocate_func)(q); + if (str == NULL) { + fprintf (stderr, "Error in mpfr_get_str: no more memory available\n"); + exit (1); + } + } if (neg) *str++='-'; mpz_get_str(str, base, bz); /* n digits of mantissa */ - if (strlen(str)==n+1) f++; /* possible due to rounding */ + if (strlen(str)==n+1) { + f++; /* possible due to rounding */ + str[n]='\0'; /* ensures we get only n digits of output */ + } + else if (strlen(str)==n-1) { + f--; + str[n-1]='0'; + str[n]='\0'; + } *expptr = f; mpfr_clear(a); mpfr_clear(b); mpz_clear(bz); return str0; diff --git a/mpfr/init.c b/mpfr/init.c index 37f03536c..7f95c4159 100644 --- a/mpfr/init.c +++ b/mpfr/init.c @@ -1,6 +1,6 @@ /* mpfr_init -- initialize a floating-point number -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -23,27 +23,44 @@ MA 02111-1307, USA. */ #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" void #if __STDC__ -mpfr_init2 (mpfr_t x, unsigned long int p) +mpfr_init2 (mpfr_ptr x, mp_prec_t p) #else mpfr_init2 (x, p) - mpfr_t x; - unsigned long int p; + mpfr_ptr x; + mp_prec_t p; #endif { - unsigned long xsize; + mp_prec_t xsize; if (p==0) { - printf("*** cannot initialize mpfr with precision 0\n"); exit(1); + fprintf(stderr, "*** cannot initialize mpfr with precision 0\n"); exit(1); } xsize = (p - 1)/BITS_PER_MP_LIMB + 1; - x -> _mp_prec = p; - x -> _mp_d = (mp_ptr) (*__gmp_allocate_func) - (xsize * BYTES_PER_MP_LIMB); - x -> _mp_size = xsize; - x -> _mp_exp = 0; /* avoids uninitialized memory reads for zero */ + MPFR_PREC(x) = p; + MPFR_MANT(x) = (mp_ptr) (*_mp_allocate_func) (xsize * BYTES_PER_MP_LIMB); + if (MPFR_MANT(x) == NULL) { + fprintf (stderr, "Error in mpfr_init2: no more memory available\n"); + exit (1); + } + MPFR_SIZE(x) = xsize; + MPFR_CLEAR_FLAGS(x); + MPFR_SET_ZERO(x); /* initializes to zero */ + MPFR_EXP(x) = 0; /* avoids uninitialized memory reads for zero */ +} + +void +#if __STDC__ +mpfr_init (mpfr_ptr x) +#else +mpfr_init (x) + mpfr_ptr x; +#endif +{ + mpfr_init2(x, __gmp_default_fp_bit_precision); } diff --git a/mpfr/inp_str.c b/mpfr/inp_str.c new file mode 100644 index 000000000..3a6d847f9 --- /dev/null +++ b/mpfr/inp_str.c @@ -0,0 +1,105 @@ +/* mpf_inp_str(dest_float, stream, base) -- Input a number in base + BASE from stdio stream STREAM and store the result in DEST_FLOAT. + +Copied from GMP, file mpf/inp_str.c. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <ctype.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +size_t +#if __STDC__ +mpfr_inp_str (mpfr_ptr rop, FILE *stream, int base, mp_rnd_t rnd_mode) +#else +mpfr_inp_str (rop, stream, base, rnd_mode) + mpfr_ptr rop; + FILE *stream; + int base; + mp_rnd_t rnd_mode; +#endif +{ + char *str; + size_t alloc_size, str_size; + int c; + size_t retval; + size_t nread; + + MPFR_CLEAR_FLAGS(rop); + if (stream == 0) + stream = stdin; + + alloc_size = 100; + str = (char *) (*_mp_allocate_func) (alloc_size); + if (str == NULL) { + fprintf (stderr, "Error in mpfr_inp_str: no more memory available\n"); + exit (1); + } + str_size = 0; + nread = 0; + + /* Skip whitespace. */ + do + { + c = getc (stream); + nread++; + } + while (isspace (c)); + + for (;;) + { + if (str_size >= alloc_size) + { + size_t old_alloc_size = alloc_size; + alloc_size = alloc_size * 3 / 2; + str = (char *) (*_mp_reallocate_func) (str, old_alloc_size, alloc_size); + if (str == NULL) { + fprintf (stderr, "Error in mpfr_inp_str: no more memory available\n"); + exit (1); + } + } + if (c == EOF || isspace (c)) + break; + str[str_size++] = c; + c = getc (stream); + } + ungetc (c, stream); + + if (str_size >= alloc_size) + { + size_t old_alloc_size = alloc_size; + alloc_size = alloc_size * 3 / 2; + str = (char *) (*_mp_reallocate_func) (str, old_alloc_size, alloc_size); + if (str == NULL) { + fprintf (stderr, "Error in mpfr_inp_str: no more memory available\n"); + exit (1); + } + } + str[str_size] = 0; + + retval = mpfr_set_str (rop, str, base, rnd_mode); + if (retval == -1) + return 0; /* error */ + + (*_mp_free_func) (str, alloc_size); + return str_size + nread; +} diff --git a/mpfr/log.c b/mpfr/log.c index 06f5dad03..523d19870 100644 --- a/mpfr/log.c +++ b/mpfr/log.c @@ -1,6 +1,6 @@ /* mpfr_log -- natural logarithm of a floating-point number -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -20,11 +20,10 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <stdio.h> -#include <math.h> #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" - +#include "mpfr-impl.h" /* The computation of log(a) is done using the formula : if we want p bits of the result, @@ -40,44 +39,66 @@ MA 02111-1307, USA. */ so the relative error 4/s^2 is < 4/2^p i.e. 4 ulps. */ - -#define MON_INIT(xp, x, p, s) xp = (mp_ptr) TMP_ALLOC(s*BYTES_PER_MP_LIMB); x -> _mp_prec = p; x -> _mp_d = xp; x -> _mp_size = s; x -> _mp_exp = 0; - /* #define DEBUG */ int #if __STDC__ -mpfr_log(mpfr_ptr r, mpfr_srcptr a, unsigned char rnd_mode) +mpfr_log (mpfr_ptr r, mpfr_srcptr a, mp_rnd_t rnd_mode) #else -mpfr_log(r, a, rnd_mode) +mpfr_log (r, a, rnd_mode) mpfr_ptr r; mpfr_srcptr a; - unsigned char rnd_mode; + mp_rnd_t rnd_mode; #endif { - int p, m, q, bool, size, cancel; + int m, bool, size, cancel; + mp_prec_t p, q; mpfr_t cst, rapport, agm, tmp1, tmp2, s, mm; mp_limb_t *cstp, *rapportp, *agmp, *tmp1p, *tmp2p, *sp, *mmp; double ref; TMP_DECL(marker); - /* If a is NaN or a is negative or null, the result is NaN */ - if (FLAG_NAN(a) || (SIGN(a)<=0)) - { SET_NAN(r); return 1; } + /* If a is NaN, the result is NaN */ + if (MPFR_IS_NAN(a)) { + MPFR_SET_NAN(r); + return 1; + } + + MPFR_CLEAR_NAN(r); + + /* check for infinity before zero */ + if (MPFR_IS_INF(a)) + { + MPFR_SET_INF(r); + if (MPFR_SIGN(r) > 0) MPFR_CHANGE_SIGN(r); + return 1; + } + + if (MPFR_IS_ZERO(a)) + { + MPFR_SET_INF(r); + if (MPFR_SIGN(r) < 0) MPFR_CHANGE_SIGN(r); + return 1; + } + + /* Now we can clear the flags without damage even if r == a */ + MPFR_CLEAR_INF(r); /* If a is 1, the result is 0 */ if (mpfr_cmp_ui_2exp(a,1,0)==0){ - SET_ZERO(r); + MPFR_SET_ZERO(r); return 0; /* only case where the result is exact */ } - q=PREC(r); + q=MPFR_PREC(r); ref=mpfr_get_d(a)-1.0; if (ref<0) ref=-ref; - p=q+4; + /* use initial precision about q+lg(q)+5 */ + p=q+5; m=q; while (m) { p++; m >>= 1; } + /* adjust to entire limb */ if (p%BITS_PER_MP_LIMB) p += BITS_PER_MP_LIMB - (p%BITS_PER_MP_LIMB); @@ -89,33 +110,33 @@ mpfr_log(r, a, rnd_mode) printf("p=%d\n", p); #endif /* Calculus of m (depends on p) */ - m=(int) ceil(((double) p)/2.0) -EXP(a)+1; + m = (p + 1) / 2 - MPFR_EXP(a) + 1; /* All the mpfr_t needed have a precision of p */ TMP_MARK(marker); size=(p-1)/BITS_PER_MP_LIMB+1; - MON_INIT(cstp, cst, p, size); - MON_INIT(rapportp, rapport, p, size); - MON_INIT(agmp, agm, p, size); - MON_INIT(tmp1p, tmp1, p, size); - MON_INIT(tmp2p, tmp2, p, size); - MON_INIT(sp, s, p, size); - MON_INIT(mmp, mm, p, size); - - mpfr_set_si(mm,m,GMP_RNDN); /* I have m, supposed exact */ - mpfr_set_si(tmp1,1,GMP_RNDN); /* I have 1, exact */ - mpfr_set_si(tmp2,4,GMP_RNDN); /* I have 4, exact */ - mpfr_mul_2exp(s,a,m,GMP_RNDN); /* I compute s=a*2^m, err <= 1 ulp */ - mpfr_div(rapport,tmp2,s,GMP_RNDN); /* I compute 4/s, err <= 2 ulps */ - mpfr_agm(agm,tmp1,rapport,GMP_RNDN); /* AG(1,4/s), err<=3 ulps */ - mpfr_mul_2exp(tmp1,agm,1,GMP_RNDN); /* 2*AG(1,4/s), still err<=3 ulps */ - mpfr_pi(cst, GMP_RNDN); /* I compute pi, err<=1ulp */ - mpfr_div(tmp2,cst,tmp1,GMP_RNDN); /* pi/2*AG(1,4/s), err<=5ulps */ - mpfr_log2(cst,GMP_RNDN); /* I compute log(2), err<=1ulp */ + MPFR_INIT(cstp, cst, p, size); + MPFR_INIT(rapportp, rapport, p, size); + MPFR_INIT(agmp, agm, p, size); + MPFR_INIT(tmp1p, tmp1, p, size); + MPFR_INIT(tmp2p, tmp2, p, size); + MPFR_INIT(sp, s, p, size); + MPFR_INIT(mmp, mm, p, size); + + mpfr_set_si (mm, m, GMP_RNDN); /* I have m, supposed exact */ + mpfr_set_si (tmp1, 1, GMP_RNDN); /* I have 1, exact */ + mpfr_set_si (tmp2, 4, GMP_RNDN); /* I have 4, exact */ + mpfr_mul_2exp (s, a, m, GMP_RNDN); /* I compute s=a*2^m, err <= 1 ulp */ + mpfr_div (rapport, tmp2, s, GMP_RNDN);/* I compute 4/s, err <= 2 ulps */ + mpfr_agm (agm, tmp1, rapport, GMP_RNDN); /* AG(1,4/s), err<=3 ulps */ + mpfr_mul_2exp (tmp1, agm, 1, GMP_RNDN); /* 2*AG(1,4/s), still err<=3 ulps */ + mpfr_const_pi (cst, GMP_RNDN); /* compute pi, err<=1ulp */ + mpfr_div (tmp2, cst, tmp1, GMP_RNDN); /* pi/2*AG(1,4/s), err<=5ulps */ + mpfr_const_log2 (cst, GMP_RNDN); /* compute log(2), err<=1ulp */ mpfr_mul(tmp1,cst,mm,GMP_RNDN); /* I compute m*log(2), err<=2ulps */ - cancel = EXP(tmp2); + cancel = MPFR_EXP(tmp2); mpfr_sub(cst,tmp2,tmp1,GMP_RNDN); /* log(a), err<=7ulps+cancel */ - cancel -= EXP(cst); + cancel -= MPFR_EXP(cst); #ifdef DEBUG printf("cancelled bits=%d\n", cancel); printf("approx="); mpfr_print_raw(cst); putchar('\n'); diff --git a/mpfr/log2.c b/mpfr/log2.c index 151e0e8cb..0c8688eac 100644 --- a/mpfr/log2.c +++ b/mpfr/log2.c @@ -1,6 +1,6 @@ -/* mpfr_log2 -- compute natural logarithm of 2 +/* mpfr_const_log2 -- compute natural logarithm of 2 -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -20,16 +20,99 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <stdio.h> -#include <math.h> #include "gmp.h" -#include "gmp-impl.h" #include "longlong.h" #include "mpfr.h" +#include "gmp-impl.h" +#include "mpfr-impl.h" + +mpfr_t __mpfr_const_log2; /* stored value of log(2) */ +int __mpfr_const_log2_prec=0; /* precision of stored value */ +mp_rnd_t __mpfr_const_log2_rnd; /* rounding mode of stored value */ + +int mpfr_aux_log2 (mpfr_ptr, mpz_srcptr, int, int); +int mpfr_const_aux_log2 (mpfr_ptr, mp_rnd_t); + +#define A +#define A1 1 +#define A2 1 +#undef B +#define C +#define C1 2 +#define C2 1 +#define NO_FACTORIAL +#undef R_IS_RATIONAL +#define GENERIC mpfr_aux_log2 +#include "generic.c" +#undef A +#undef A1 +#undef A2 +#undef NO_FACTORIAL +#undef GENERIC +#undef C +#undef C1 +#undef C2 + +int +#if __STDC__ +mpfr_const_aux_log2 (mpfr_ptr mylog, mp_rnd_t rnd_mode) +#else +mpfr_const_aux_log2 (mylog, rnd_mode) + mpfr_ptr mylog; + mp_rnd_t rnd_mode; +#endif +{ + int prec; + mpfr_t tmp1, tmp2, result,tmp3; + mpz_t cst; + int good = 0; + int logn; + int prec_i_want = MPFR_PREC(mylog); + int prec_x; + + mpz_init(cst); + logn = _mpfr_ceil_log2 ((double) MPFR_PREC(mylog)); + prec_x = prec_i_want + logn; + while (!good){ + prec = _mpfr_ceil_log2 ((double) prec_x); + mpfr_init2(tmp1, prec_x); + mpfr_init2(result, prec_x); + mpfr_init2(tmp2, prec_x); + mpfr_init2(tmp3, prec_x); + mpz_set_ui(cst, 1); + mpfr_aux_log2(tmp1, cst, 4, prec-2); + mpfr_div_2exp(tmp1, tmp1, 4,GMP_RNDD); + mpfr_mul_ui(tmp1, tmp1, 15,GMP_RNDD); + + mpz_set_ui(cst, 3); + mpfr_aux_log2(tmp2, cst, 7, prec-2); + mpfr_div_2exp(tmp2, tmp2, 7,GMP_RNDD); + mpfr_mul_ui(tmp2, tmp2, 5*3,GMP_RNDD); + mpfr_sub(result, tmp1, tmp2, GMP_RNDD); + + mpz_set_ui(cst, 13); + mpfr_aux_log2(tmp3, cst, 8, prec-2); + mpfr_div_2exp(tmp3, tmp3, 8,GMP_RNDD); + mpfr_mul_ui(tmp3, tmp3, 3*13,GMP_RNDD); + mpfr_sub(result, result, tmp3, GMP_RNDD); + + mpfr_clear(tmp1); + mpfr_clear(tmp2); + mpfr_clear(tmp3); + if (mpfr_can_round(result, prec_x, GMP_RNDD, rnd_mode, prec_i_want)){ + mpfr_set(mylog, result, rnd_mode); + good = 1; + } else + { + prec_x += logn; + } + mpfr_clear(result); + } + mpz_clear(cst); + return 0; +} -mpfr_t __mpfr_log2; /* stored value of log(2) with rnd_mode=GMP_RNDZ */ -int __mpfr_log2_prec=0; /* precision of stored value */ - -/* set x to log(2) rounded to precision PREC(x) with direction rnd_mode +/* set x to log(2) rounded to precision MPFR_PREC(x) with direction rnd_mode use formula log(2) = sum(1/k/2^k, k=1..infinity) @@ -44,59 +127,58 @@ int __mpfr_log2_prec=0; /* precision of stored value */ */ void #if __STDC__ -mpfr_log2(mpfr_ptr x, unsigned char rnd_mode) +mpfr_const_log2 (mpfr_ptr x, mp_rnd_t rnd_mode) #else -mpfr_log2(x, rnd_mode) mpfr_ptr x; unsigned char rnd_mode; +mpfr_const_log2 (x, rnd_mode) mpfr_ptr x; mp_rnd_t rnd_mode; #endif { int N, oldN, k, precx; mpz_t s, t, u; - precx = PREC(x); + precx = MPFR_PREC(x); + MPFR_CLEAR_FLAGS(x); /* has stored value enough precision ? */ - if (precx <= __mpfr_log2_prec) { - if (rnd_mode==GMP_RNDZ || rnd_mode==GMP_RNDD || - mpfr_can_round(__mpfr_log2, __mpfr_log2_prec, GMP_RNDZ, rnd_mode, precx)) + if (precx <= __mpfr_const_log2_prec) { + if (rnd_mode==__mpfr_const_log2_rnd || mpfr_can_round(__mpfr_const_log2, + __mpfr_const_log2_prec, __mpfr_const_log2_rnd, rnd_mode, precx)) { - mpfr_set(x, __mpfr_log2, rnd_mode); return; + mpfr_set(x, __mpfr_const_log2, rnd_mode); return; } } /* need to recompute */ - N=2; - do { - oldN = N; - N = precx + (int)ceil(log((double)N)/log(2.0)); - } while (N != oldN); - mpz_init_set_ui(s,0); - mpz_init(u); - mpz_init_set_ui(t,1); -#if 0 - /* use log(2) = sum(1/k/2^k, k=1..infinity) */ - mpz_mul_2exp(t, t, N); - for (k=1;k<N;k++) { - mpz_div_2exp(t, t, 1); - mpz_fdiv_q_ui(u, t, k); - mpz_add(s, s, u); - } -#else - /* use log(2) = sum((6*k-1)/(2*k^2-k)/2^(2*k+1), k=1..infinity) */ - mpz_mul_2exp(t, t, N-1); - for (k=1;k<N/2;k++) { - mpz_div_2exp(t, t, 2); - mpz_mul_ui(u, t, 6*k-1); - mpz_fdiv_q_ui(u, u, k*(2*k-1)); - mpz_add(s, s, u); - } -#endif - mpfr_set_z(x, s, rnd_mode); - EXP(x) -= N; - - /* stored computed value */ - if (__mpfr_log2_prec==0) mpfr_init2(__mpfr_log2, precx); - else mpfr_set_prec(__mpfr_log2, precx); - mpfr_set(__mpfr_log2, x, GMP_RNDZ); - __mpfr_log2_prec=precx; - - mpz_clear(s); mpz_clear(t); mpz_clear(u); + if (precx < 30000){ /* use nai"ve Taylor series evaluation */ + N=2; + do { + oldN = N; + N = precx + _mpfr_ceil_log2 ((double) N); + } while (N != oldN); + mpz_init (s); /* set to zero */ + mpz_init (u); + mpz_init_set_ui (t, 1); + + /* use log(2) = sum((6*k-1)/(2*k^2-k)/2^(2*k+1), k=1..infinity) */ + mpz_mul_2exp (t, t, N-1); + for (k=1; k<N/2; k++) { + mpz_div_2exp (t, t, 2); + mpz_mul_ui (u, t, 6*k-1); + mpz_fdiv_q_ui (u, u, k*(2*k-1)); + mpz_add (s, s, u); + } + + mpfr_set_z(x, s, rnd_mode); + MPFR_EXP(x) -= N; + mpz_clear(s); mpz_clear(t); mpz_clear(u); + } else + { + /* use binary splitting method */ + mpfr_const_aux_log2(x, rnd_mode); + } + + /* store computed value */ + if (__mpfr_const_log2_prec==0) mpfr_init2(__mpfr_const_log2, precx); + else mpfr_set_prec(__mpfr_const_log2, precx); + mpfr_set(__mpfr_const_log2, x, rnd_mode); + __mpfr_const_log2_prec=precx; + __mpfr_const_log2_rnd=rnd_mode; } diff --git a/mpfr/mpf2mpfr.h b/mpfr/mpf2mpfr.h new file mode 100644 index 000000000..0e4704b8c --- /dev/null +++ b/mpfr/mpf2mpfr.h @@ -0,0 +1,144 @@ +/* types */ +#define mpf_t mpfr_t + + +#undef mpf_ceil +#undef mpf_clear +#undef mpf_cmp +#undef mpf_cmp_si +#undef mpf_cmp_ui +#undef mpf_eq +#undef mpf_floor +#undef mpf_get_d +#undef mpf_get_prec +#undef mpf_init +#undef mpf_init2 +#undef mpf_random2 +#undef mpf_set_default_prec +#undef mpf_set_prec +#undef mpf_set_prec_raw +#undef mpf_trunc +#undef mpf_sgn +#undef mpf_swap + +/* functions which take as argument the rounding mode */ +#undef mpf_abs +#undef mpf_add +#undef mpf_add_ui +#undef mpf_div +#undef mpf_div_ui +#undef mpf_div_2exp +#undef mpf_dump +#undef mpf_get_str +#undef mpf_inp_str +#undef mpf_set_str +#undef mpf_init_set +#undef mpf_init_set_d +#undef mpf_init_set_si +#undef mpf_init_set_str +#undef mpf_init_set_ui +#undef mpf_mul +#undef mpf_mul_2exp +#undef mpf_mul_ui +#undef mpf_neg +#undef mpf_out_str +#undef mpf_pow_ui +#undef mpf_reldiff +#undef mpf_set +#undef mpf_set_d +#undef mpf_set_q +#undef mpf_set_si +#undef mpf_set_ui +#undef mpf_set_z +#undef mpf_sqrt +#undef mpf_sqrt_ui +#undef mpf_sub +#undef mpf_sub_ui +#undef mpf_ui_div +#undef mpf_ui_sub +#undef mpf_urandomb + + + + + + + + + + + + + + + + + + + + + + + + +/* functions which don't take as argument the rounding mode */ +#define mpf_ceil mpfr_ceil +#define mpf_clear mpfr_clear +#define mpf_cmp mpfr_cmp +#define mpf_cmp_si mpfr_cmp_si +#define mpf_cmp_ui mpfr_cmp_ui +#define mpf_eq mpfr_eq +#define mpf_floor mpfr_floor +#define mpf_get_d mpfr_get_d +#define mpf_get_prec mpfr_get_prec +#define mpf_init mpfr_init +#define mpf_init2 mpfr_init2 +#define mpf_random2 mpfr_random2 +#define mpf_set_default_prec mpfr_set_default_prec +#define mpf_set_prec(x,p) mpfr_round(x,__gmp_default_rounding_mode,p) +#define mpf_set_prec_raw mpfr_set_prec_raw +#define mpf_trunc mpfr_trunc +#define mpf_sgn mpfr_sgn +#define mpf_swap mpfr_swap + +/* functions which take as argument the rounding mode */ +#define mpf_abs(x,y) mpfr_abs(x,y,__gmp_default_rounding_mode) +#define mpf_add(x,y,z) mpfr_add(x,y,z,__gmp_default_rounding_mode) +#define mpf_add_ui(x,y,z) \ + mpfr_add_ui(x,y,z,__gmp_default_rounding_mode) +#define mpf_div(x,y,z) mpfr_div(x,y,z,__gmp_default_rounding_mode) +#define mpf_div_ui(x,y,z) \ + mpfr_div_ui(x,y,z,__gmp_default_rounding_mode) +#define mpf_div_2exp(x,y,z) \ + mpfr_div_2exp(x,y,z,__gmp_default_rounding_mode) +#define mpf_dump(x,y,z) \ + mpfr_dump(x,y,z,__gmp_default_rounding_mode) +#define mpf_get_str(x,y,z,t,u) \ + mpfr_get_str(x,y,z,t,u,__gmp_default_rounding_mode) +#define mpf_inp_str(x,y,z) mpfr_inp_str(x,y,z,__gmp_default_rounding_mode) +#define mpf_set_str(x,y,z) mpfr_set_str(x,y,z,__gmp_default_rounding_mode) +#define mpf_init_set(x,y) mpfr_init_set(x,y,__gmp_default_rounding_mode) +#define mpf_init_set_d(x,y) mpfr_init_set_d(x,y,__gmp_default_rounding_mode) +#define mpf_init_set_si(x,y) mpfr_init_set_si(x,y,__gmp_default_rounding_mode) +#define mpf_init_set_str(x,y,z) mpfr_init_set_str(x,y,z,__gmp_default_rounding_mode) +#define mpf_init_set_ui(x,y) mpfr_init_set_ui(x,y,__gmp_default_rounding_mode) +#define mpf_mul(x,y,z) mpfr_mul(x,y,z,__gmp_default_rounding_mode) +#define mpf_mul_2exp(x,y,z) mpfr_mul_2exp(x,y,z,__gmp_default_rounding_mode) +#define mpf_mul_ui(x,y,z) mpfr_mul_ui(x,y,z,__gmp_default_rounding_mode) +#define mpf_neg(x,y) mpfr_neg(x,y,__gmp_default_rounding_mode) +#define mpf_out_str(x,y,z,t) mpfr_out_str(x,y,z,t,__gmp_default_rounding_mode) +#define mpf_pow_ui(x,y,z) mpfr_pow_ui(x,y,z,__gmp_default_rounding_mode) +#define mpf_reldiff(x,y,z) mpfr_reldiff(x,y,z,__gmp_default_rounding_mode) +#define mpf_set(x,y) mpfr_set(x,y,__gmp_default_rounding_mode) +#define mpf_set_d(x,y) mpfr_set_d(x,y,__gmp_default_rounding_mode) +#define mpf_set_q(x,y) mpfr_set_q(x,y,__gmp_default_rounding_mode) +#define mpf_set_si(x,y) mpfr_set_si(x,y,__gmp_default_rounding_mode) +#define mpf_set_ui(x,y) mpfr_set_ui(x,y,__gmp_default_rounding_mode) +#define mpf_set_z(x,y) mpfr_set_z(x,y,__gmp_default_rounding_mode) +#define mpf_sqrt(x,y) mpfr_sqrt(x,y,__gmp_default_rounding_mode) +#define mpf_sqrt_ui(x,y) mpfr_sqrt_ui(x,y,__gmp_default_rounding_mode) +#define mpf_sub(x,y,z) mpfr_sub(x,y,z,__gmp_default_rounding_mode) +#define mpf_sub_ui(x,y,z) mpfr_sub_ui(x,y,z,__gmp_default_rounding_mode) +#define mpf_ui_div(x,y,z) mpfr_ui_div(x,y,z,__gmp_default_rounding_mode) +#define mpf_ui_sub(x,y,z) mpfr_ui_sub(x,y,z,__gmp_default_rounding_mode) +#define mpf_urandomb(x,y,n) mpfr_urandomb(x,y) diff --git a/mpfr/mpfr-impl.h b/mpfr/mpfr-impl.h index 3464febb1..5303b8068 100644 --- a/mpfr/mpfr-impl.h +++ b/mpfr/mpfr-impl.h @@ -1,6 +1,6 @@ /* Utilities for MPFR developers, not exported. -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999-2000 Free Software Foundation. This file is part of the MPFR Library. @@ -19,40 +19,97 @@ along with the MPFR Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include <math.h> -/* generate a random double using the whole range of possible values, - including denormalized numbers, NaN, infinities, ... */ -double drand() -{ - volatile double d; int *i; +/* Fudges */ +#define _mp_allocate_func __gmp_allocate_func +#define _mp_reallocate_func __gmp_reallocate_func +#define _mp_free_func __gmp_free_func +#define _mp_default_allocate __gmp_default_allocate +#define _mp_default_reallocate __gmp_default_reallocate +#define _mp_default_free __gmp_default_free - i = (int*) &d; - i[0] = mrand48(); - i[1] = mrand48(); - return d; -} -/* returns the number of ulp's between a and b */ -int ulp(a,b) double a,b; -{ - double eps=1.1102230246251565404e-16; /* 2^(-53) */ - if (a==0.0) { - if (b==0.0) return 0; - else if (b<0.0) return 2147483647; - else return -2147483647; - } - b = (a-b)/a; - if (b>0) - return (int) floor(b/eps); - else - return (int) ceil(b/eps); -} -/* return double m*2^e */ -double dbl(m,e) double m; int e; -{ - if (e>=0) while (e-->0) m *= 2.0; - else while (e++<0) m /= 2.0; - return m; + + +/* Definition of constants */ + +#define LOG2 0.69314718055994528622 /* log(2) rounded to zero on 53 bits */ + +/* macros for doubles, based on gmp union ieee_double_extract */ + +typedef union ieee_double_extract Ieee_double_extract; + +#define DOUBLE_ISNANorINF(x) (((Ieee_double_extract *)&(x))->s.exp == 0x7ff) +#define DOUBLE_ISINF(x) (DOUBLE_ISNANorINF(x) && \ + (((Ieee_double_extract *)&(x))->s.manl == 0) && \ + (((Ieee_double_extract *)&(x))->s.manh == 0)) +#define DOUBLE_ISNAN(x) (DOUBLE_ISNANorINF(x) && \ + ((((Ieee_double_extract *)&(x))->s.manl != 0) || \ + (((Ieee_double_extract *)&(x))->s.manh != 0))) + +/* bit 31 of _mpfr_size is used for sign, + bit 30 of _mpfr_size is used for Nan flag, + bit 29 of _mpfr_size is used for Inf flag, + remaining bits are used to store the number of allocated limbs */ +#define MPFR_CLEAR_FLAGS(x) (((x) -> _mpfr_size &= ~(3 << 29))) +#define MPFR_IS_NAN(x) (((x)->_mpfr_size >> 30)&1) +#define MPFR_SET_NAN(x) ((x)->_mpfr_size |= (1<<30)) +#define MPFR_CLEAR_NAN(x) (((x) -> _mpfr_size &= ~(1 << 30))) +#define MPFR_IS_INF(x) (((x)->_mpfr_size >> 29)&1) +#define MPFR_SET_INF(x) ((x)->_mpfr_size |= (1<<29)) +#define MPFR_CLEAR_INF(x) ((x)->_mpfr_size &= ~(1 << 29)) +#define MPFR_IS_FP(x) ((((x) -> _mpfr_size >> 29) & 3) == 0) +#define MPFR_ABSSIZE(x) ((x)->_mpfr_size & ((1<<29)-1)) +#define MPFR_SIZE(x) ((x)->_mpfr_size) +#define MPFR_EXP(x) ((x)->_mpfr_exp) +#define MPFR_MANT(x) ((x)->_mpfr_d) +#define MPFR_ISNONNEG(x) (MPFR_NOTZERO((x)) && MPFR_SIGN(x)>=0) +#define MPFR_ISNEG(x) (MPFR_NOTZERO((x)) && MPFR_SIGN(x)==-1) +#define MPFR_CHANGE_SIGN(x) (MPFR_SIZE(x) ^= (((mp_size_t)1)<<31)) +#define MPFR_SET_SAME_SIGN(x, y) if (MPFR_SIGN((x)) != MPFR_SIGN((y))) { MPFR_CHANGE_SIGN((x)); } +#define MPFR_PREC(x) ((x)->_mpfr_prec) +#define MPFR_NOTZERO(x) (MPFR_MANT(x)[(MPFR_PREC(x)-1)/BITS_PER_MP_LIMB]) +#define MPFR_IS_ZERO(x) ((MPFR_NOTZERO(x))==0) +#define MPFR_SET_ZERO(x) (MPFR_MANT(x)[(MPFR_PREC(x)-1)/BITS_PER_MP_LIMB] = 0) +#define mpfr_sgn(x) ((MPFR_NOTZERO(x)) ? MPFR_SIGN(x) : 0) + +/* Memory gestion */ + +/* temporary allocate s limbs at xp, and initialize mpfr variable x */ +#define MPFR_INIT(xp, x, p, s) xp = (mp_ptr) TMP_ALLOC(s*BYTES_PER_MP_LIMB); \ + MPFR_PREC(x) = p; MPFR_MANT(x) = xp; MPFR_SIZE(x) = s; MPFR_EXP(x) = 0; +/* same when xp is already allocated */ +#define MPFR_INIT1(xp, x, p, s) \ + MPFR_PREC(x)=p; MPFR_MANT(x)=xp; MPFR_SIZE(x)=s; + +#ifndef _PROTO +#if defined (__STDC__) || defined (__cplusplus) +#define _PROTO(x) x +#else +#define _PROTO(x) () +#endif +#endif + +#if defined (__cplusplus) +extern "C" { +#endif + +int mpfr_round_raw _PROTO ((mp_limb_t *, mp_limb_t *, mp_prec_t, int, + mp_prec_t, mp_rnd_t)); +int mpfr_round_raw2 _PROTO((mp_limb_t *, mp_prec_t, int, mp_rnd_t, mp_prec_t)); +int mpfr_can_round_raw _PROTO ((mp_limb_t *, mp_prec_t, int, mp_prec_t, + mp_rnd_t, mp_rnd_t, mp_prec_t)); +double mpfr_get_d2 _PROTO ((mpfr_srcptr, long)); +mp_size_t mpn_sqrtrem_new _PROTO ((mp_limb_t *, mp_limb_t *, mp_limb_t *, mp_size_t)); +int mpfr_cmp2 _PROTO ((mpfr_srcptr, mpfr_srcptr)); +long _mpfr_ceil_log2 _PROTO ((double)); +long _mpfr_floor_log2 _PROTO ((double)); +double _mpfr_ceil_exp2 _PROTO ((double)); +unsigned long _mpfr_isqrt _PROTO ((unsigned long)); +unsigned long _mpfr_cuberoot _PROTO ((unsigned long)); + +#if defined (__cplusplus) } +#endif + diff --git a/mpfr/mpfr-test.h b/mpfr/mpfr-test.h new file mode 100644 index 000000000..ef9fbfb04 --- /dev/null +++ b/mpfr/mpfr-test.h @@ -0,0 +1,82 @@ +/* auxiliary functions for MPFR tests. + +Copyright (C) 1999-2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <math.h> +#ifdef __mips +#include <sys/fpu.h> +#endif + +#if defined (hpux) +#define srandom srand48 +#define random mrand48 +#endif + +double drand _PROTO((void)); +int ulp _PROTO((double, double)); +double dbl _PROTO((double, int)); + +#define MINNORM 2.2250738585072013831e-308 /* 2^(-1022), smallest normalized */ +#define MAXNORM 1.7976931348623157081e308 /* 2^(1023)*(2-2^(-52)) */ + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define ABS(x) (((x)>0) ? (x) : (-x)) + +/* generate a random double using the whole range of possible values, + including denormalized numbers, NaN, infinities, ... */ +double drand () +{ + double d; int *i, expo; + + i = (int*) &d; + d = 1.0; + if (i[0]==0) expo=1; /* little endian, exponent in i[1] */ + else expo=0; + i[0] = lrand48(); + i[1] = lrand48(); + while (i[expo]>=2146435072) i[expo] = lrand48(); /* avoids NaNs */ + if (lrand48()%2 && !isnan(d)) d=-d; /* generates negative numbers */ + return d; +} + +/* returns the number of ulp's between a and b */ +int ulp (double a, double b) +{ + double eps=1.1102230246251565404e-16; /* 2^(-53) */ + if (a==0.0) { + if (b==0.0) return 0; + else if (b<0.0) return 2147483647; + else return -2147483647; + } + b = (a-b)/a; + if (b>0) + return (int) floor(b/eps); + else + return (int) ceil(b/eps); +} + +/* return double m*2^e */ +double dbl (double m, int e) +{ + if (e>=0) while (e-->0) m *= 2.0; + else while (e++<0) m /= 2.0; + return m; +} diff --git a/mpfr/mpfr.h b/mpfr/mpfr.h index 78034affb..948b1103e 100644 --- a/mpfr/mpfr.h +++ b/mpfr/mpfr.h @@ -1,6 +1,6 @@ /* mpfr.h -- Include file for mpfr. -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -21,14 +21,6 @@ MA 02111-1307, USA. */ #include <stdio.h> -/* Cygnus does not know about *rand48 functions */ -#ifdef __CYGWIN32__ -#define mrand48 rand -#define drand48 rand -#define lrand48 rand -#define srand48 srand -#endif - /* Definition of rounding modes */ #define GMP_RNDN 0 @@ -38,32 +30,35 @@ MA 02111-1307, USA. */ /* Definitions of types and their semantics */ +typedef unsigned long int mp_prec_t; /* easy to change if necessary */ +typedef int mp_rnd_t; /* preferred to char */ + typedef struct { - unsigned long int _mp_prec; /* WARNING : for the mpfr type, the precision */ + mp_prec_t _mpfr_prec; /* WARNING : for the mpfr type, the precision */ /* should be understood as the number of BITS,*/ /* not the number of mp_limb_t's. This means */ /* that the corresponding number of allocated limbs is >= ceil(_mp_prec/BITS_PER_MP_LIMB) */ - mp_size_t _mp_size; /* abs(_mp_size) is the number of allocated + mp_size_t _mpfr_size; /* MPFR_ABSSIZE(.) is the number of allocated limbs the field _mp_d points to. - The sign is that of _mp_size. + The sign is that of _mpfr_size. The number 0 is such that _mp_d[k-1]=0 where k = ceil(_mp_prec/BITS_PER_MP_LIMB) */ - mp_exp_t _mp_exp; - mp_limb_t *_mp_d; + mp_exp_t _mpfr_exp; + mp_limb_t *_mpfr_d; } __mpfr_struct; /* The number represented is - sign(_mp_size)*(_mp_d[k-1]/B+_mp_d[k-2]/B^2+...+_mp_d[0]/B^k)*2^_mp_exp + sign(_mpfr_size)*(_mpfr_d[k-1]/B+_mpfr_d[k-2]/B^2+...+_mpfr_d[0]/B^k)*2^_mpfr_exp where k=ceil(_mp_prec/BITS_PER_MP_LIMB) and B=2^BITS_PER_MP_LIMB. For the msb (most significant bit) normalized representation, we must have - _mp_d[k-1]>=B/2, unless the number is zero (in that case its sign is still - given by sign(_mp_size)). + _mpfr_d[k-1]>=B/2, unless the number is zero (in that case its sign is still + given by sign(_mpfr_size)). We must also have the last k*BITS_PER_MP_LIMB-_mp_prec bits set to zero. */ @@ -72,6 +67,7 @@ typedef __mpfr_struct mpfr_t[1]; typedef __mpfr_struct *mpfr_ptr; typedef __gmp_const __mpfr_struct *mpfr_srcptr; +#define MPFR_SIGN(x) (((x)->_mpfr_size >> 31) ? -1 : 1) /* Prototypes */ @@ -83,122 +79,100 @@ typedef __gmp_const __mpfr_struct *mpfr_srcptr; #endif #endif -/* bit 31 of _mp_size is used for sign, - bit 30 of _mp_size is used for Nan flag, - remaining bits are used to store the number of allocated limbs */ -#define FLAG_NAN(x) (((x)->_mp_size >> 30)&1) -#define SET_NAN(x) ((x)->_mp_size |= (1<<30)) -#define ABSSIZE(x) ((x)->_mp_size & ((1<<30)-1)) -#define SIZE(x) ((x)->_mp_size) -#define EXP(x) ((x)->_mp_exp) -#define MANT(x) ((x)->_mp_d) -#define SIGN(x) (((x)->_mp_size >> 31) ? -1 : 1) -#define ISNONNEG(x) (SIGN(x)>=0) -#define ISNEG(x) (SIGN(x)==-1) -#define CHANGE_SIGN(x) (SIZE(x) = SIZE(x) ^ (1<<31)) -#define PREC(x) ((x)->_mp_prec) -#define NOTZERO(x) (MANT(x)[(PREC(x)-1)/BITS_PER_MP_LIMB]) -#define SET_ZERO(x) (MANT(x)[(PREC(x)-1)/BITS_PER_MP_LIMB] = 0) - -/* reallocates the mantissa of x to q bits and sets the precision to q */ -#define _mpfr_realloc(x, q) { \ - (x)->_mp_d = (mp_ptr) (*__gmp_reallocate_func) \ - ((x)->_mp_d, (x)->_mp_prec>>3 + 1, (q)>>3 + 1); \ - (x)->_mp_prec = q; } - -void mpfr_init2 _PROTO ((mpfr_ptr, unsigned long int)); -int mpfr_round_raw _PROTO ((mp_limb_t *, mp_limb_t *, unsigned long, char, - unsigned long, char)); -int mpfr_round_raw2 _PROTO ((mp_limb_t *, unsigned long, char, char, - unsigned long)); -void mpfr_round _PROTO ((mpfr_ptr, char, unsigned long)); -int mpfr_can_round _PROTO ((mpfr_ptr, unsigned long, unsigned char, - unsigned char, unsigned long)); -int mpfr_can_round_raw _PROTO ((mp_limb_t *, unsigned long, int, - unsigned long, - unsigned char, unsigned char, unsigned long)); -void mpfr_set_d _PROTO ((mpfr_ptr, double, unsigned char)); -int mpfr_set_z _PROTO ((mpfr_ptr, mpz_srcptr, unsigned char)); +#if defined (__cplusplus) +extern "C" { +#endif + +void mpfr_init2 _PROTO ((mpfr_ptr, mp_prec_t)); +void mpfr_init _PROTO ((mpfr_ptr)); +void mpfr_round _PROTO ((mpfr_ptr, mp_rnd_t, mp_prec_t)); +int mpfr_can_round _PROTO ((mpfr_ptr, mp_prec_t, mp_rnd_t, mp_rnd_t, + mp_prec_t)); +void mpfr_set_d _PROTO ((mpfr_ptr, double, mp_rnd_t)); +int mpfr_set_z _PROTO ((mpfr_ptr, mpz_srcptr, mp_rnd_t)); +mp_exp_t mpz_set_fr _PROTO ((mpz_ptr, mpfr_srcptr)); +void mpfr_set_q _PROTO ((mpfr_ptr, mpq_srcptr, mp_rnd_t)); double mpfr_get_d _PROTO ((mpfr_srcptr)); -double mpfr_get_d2 _PROTO ((mpfr_srcptr, long)); -void mpfr_set_f _PROTO ((mpfr_ptr, mpf_srcptr, char)); -void mpfr_set_si _PROTO ((mpfr_ptr, long, unsigned char)); -void mpfr_set_ui _PROTO ((mpfr_ptr, unsigned long, unsigned char)); +void mpfr_set_f _PROTO ((mpfr_ptr, mpf_srcptr, mp_rnd_t)); +void mpfr_set_si _PROTO ((mpfr_ptr, long, mp_rnd_t)); +void mpfr_set_ui _PROTO ((mpfr_ptr, unsigned long, mp_rnd_t)); void mpfr_print_raw _PROTO ((mpfr_srcptr)); -void mpfr_random _PROTO ((mpfr_ptr)); +void mpfr_random _PROTO ((mpfr_ptr)); +void mpfr_srandom _PROTO ((unsigned long int)); +void mpfr_random2 _PROTO ((mpfr_ptr, mp_size_t, mp_exp_t)); +void mpfr_urandomb _PROTO ((mpfr_ptr, gmp_randstate_t)); void mpfr_clear _PROTO ((mpfr_ptr)); -void mpfr_set_str_raw _PROTO ((mpfr_ptr, char *)); -void mpfr_get_str_raw _PROTO ((char *, mpfr_srcptr)); -char* mpfr_get_str _PROTO ((char *, mp_exp_t *, int, size_t, mpfr_srcptr, unsigned char)); -size_t mpfr_out_str _PROTO ((FILE *, int, size_t, mpfr_srcptr, unsigned char)); -void mpfr_mul _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, unsigned char)); -void mpfr_pow_ui _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned int, unsigned char)); -void mpfr_ui_pow_ui _PROTO ((mpfr_ptr, unsigned int, unsigned int, unsigned char)); -mp_limb_t mpn_divrem_n _PROTO ((mp_limb_t *, mp_limb_t *, mp_limb_t *, mp_size_t)); -mp_size_t kara_sqrtrem _PROTO ((mp_limb_t *, mp_limb_t *, mp_limb_t *, mp_size_t)); -void mpfr_div _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, unsigned char)); -void mpfr_agm _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, unsigned char)); -int mpfr_sqrt _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned char)); -void mpfr_add _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, unsigned char)); -int mpfr_add_one_ulp _PROTO ((mpfr_ptr)); -void mpfr_sub _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, unsigned char)); -void mpfr_set4 _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned char, int)); -void mpfr_pi _PROTO ((mpfr_ptr, unsigned char)); -void mpfr_log2 _PROTO ((mpfr_ptr, unsigned char)); -int mpfr_log _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned char)); -int mpfr_exp _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned char)); -int mpfr_zeta _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned char)); -void mpfr_mul_ui _PROTO((mpfr_ptr, mpfr_srcptr, unsigned long, unsigned char)); -void mpfr_set_machine_rnd_mode _PROTO ((unsigned char)); -int mpfr_cmp3 _PROTO ((mpfr_srcptr, mpfr_srcptr, long int)); +void mpfr_set_str_raw _PROTO ((mpfr_ptr, char *)); +int mpfr_set_str _PROTO ((mpfr_ptr, char *, int, mp_rnd_t)); +int mpfr_init_set_str _PROTO ((mpfr_ptr, char *, int, mp_rnd_t)); +size_t mpfr_inp_str _PROTO ((mpfr_ptr, FILE *, int, mp_rnd_t)); +char* mpfr_get_str _PROTO ((char *, mp_exp_t *, int, size_t, mpfr_srcptr, mp_rnd_t)); +size_t mpfr_out_str _PROTO ((FILE *, int, size_t, mpfr_srcptr, mp_rnd_t)); +void mpfr_mul _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t)); +int mpfr_pow_ui _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned long int, mp_rnd_t)); +int mpfr_ui_pow_ui _PROTO ((mpfr_ptr, unsigned long int, unsigned long int, + mp_rnd_t)); +void mpfr_div _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t)); +void mpfr_agm _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t)); +int mpfr_sqrt _PROTO ((mpfr_ptr, mpfr_srcptr, mp_rnd_t)); +int mpfr_sqrt_ui _PROTO ((mpfr_ptr, unsigned long, mp_rnd_t)); +void mpfr_add _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t)); +void mpfr_add_ui _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned long, mp_rnd_t)); +void mpfr_sub_ui _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned long, mp_rnd_t)); +void mpfr_add_one_ulp _PROTO ((mpfr_ptr)); +void mpfr_sub _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t)); +void mpfr_ui_sub _PROTO ((mpfr_ptr, unsigned long, mpfr_srcptr, mp_rnd_t)); +void mpfr_reldiff _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t)); +void mpfr_const_pi _PROTO ((mpfr_ptr, mp_rnd_t)); +void mpfr_const_log2 _PROTO ((mpfr_ptr, mp_rnd_t)); +int mpfr_log _PROTO ((mpfr_ptr, mpfr_srcptr, mp_rnd_t)); +int mpfr_exp _PROTO ((mpfr_ptr, mpfr_srcptr, mp_rnd_t)); +int mpfr_sin_cos _PROTO ((mpfr_ptr, mpfr_ptr, mpfr_srcptr, mp_rnd_t)); +void mpfr_mul_ui _PROTO((mpfr_ptr, mpfr_srcptr, unsigned long int, mp_rnd_t)); +void mpfr_set_machine_rnd_mode _PROTO ((mp_rnd_t)); int mpfr_cmp_ui_2exp _PROTO ((mpfr_srcptr, unsigned long int, int)); int mpfr_cmp_si_2exp _PROTO ((mpfr_srcptr, long int, int)); -int mpfr_cmp2 _PROTO ((mpfr_srcptr, mpfr_srcptr)); -void mpfr_mul_2exp _PROTO((mpfr_ptr, mpfr_srcptr, unsigned long int,unsigned char)); -void mpfr_div_2exp _PROTO((mpfr_ptr, mpfr_srcptr, unsigned long int,unsigned char)); -void mpfr_set_prec _PROTO((mpfr_ptr, unsigned long int)); -void mpfr_set_default_prec _PROTO((unsigned long int)); -extern mp_size_t __gmp_default_fp_bit_precision; -extern char __gmp_default_rounding_mode; -char * mpfr_print_rnd_mode _PROTO((unsigned char)); -void mpfr_neg _PROTO((mpfr_ptr, mpfr_srcptr, unsigned char)); -int mpfr_sub_one_ulp _PROTO((mpfr_ptr x)); -int mpfr_div_ui _PROTO((mpfr_ptr y, mpfr_srcptr x, unsigned long u, unsigned char rnd_mode)); -unsigned long int mpfr_get_prec _PROTO((mpfr_t x)); - -#define mpfr_init(x) mpfr_init2(x, __gmp_default_fp_bit_precision) -#define mpfr_cmp_ui(b,i) mpfr_cmp_ui_2exp(b,i,0) -#define mpfr_cmp_si(b,i) mpfr_cmp_si_2exp(b,i,0) -#define mpfr_set(a,b,r) mpfr_set4(a,b,r,SIGN(b)) -#define mpfr_cmp(b,c) mpfr_cmp3(b,c,1) - -#if (BITS_PER_MP_LIMB==32) -#define MPFR_LIMBS_PER_DOUBLE 2 -#elif (BITS_PER_MP_LIMB==64) -#define MPFR_LIMBS_PER_DOUBLE 1 -#endif - -/* gmp-2.0.2 had only one threshold for both multiplication and squaring */ -#ifndef KARATSUBA_MUL_THRESHOLD -#ifdef KARATSUBA_THRESHOLD -#define KARATSUBA_MUL_THRESHOLD KARATSUBA_THRESHOLD -#else -#define KARATSUBA_MUL_THRESHOLD 16 -#endif -#endif - -#define mpfr_init_set_si(x, i, p, rnd) \ - mpfr_init2((x), (p)); mpfr_set_si((x), (i), (rnd)); -#define mpfr_init_set_ui(x, i, p, rnd) \ - mpfr_init2((x), (p)); mpfr_set_ui((x), (i), (rnd)); -#define mpfr_init_set_d(x, d, p, rnd) \ - mpfr_init2((x), (p)); mpfr_set_d((x), (d), (rnd)); -#define mpfr_init_set(x, y, p, rnd) \ - mpfr_init2((x), (p)); mpfr_set((x), (y), (rnd)); -#define mpfr_init_set_f(x, y, p, rnd) \ - mpfr_init2((x), (p)); mpfr_set_f((x), (y), (rnd)); -#define mpfr_init_set_str(x, y, p, rnd) \ - mpfr_init2((x), (p)); mpfr_set_str((x), (y), (rnd)); -#define mpfr_init_set_str_raw(x, y, p, rnd) \ - mpfr_init2((x), (p)); mpfr_set_str_raw((x), (y), (rnd)); +void mpfr_mul_2exp _PROTO((mpfr_ptr, mpfr_srcptr, unsigned long int,mp_rnd_t)); +void mpfr_div_2exp _PROTO((mpfr_ptr, mpfr_srcptr, unsigned long int,mp_rnd_t)); +void mpfr_set_prec _PROTO((mpfr_ptr, mp_prec_t)); +void mpfr_set_prec_raw _PROTO((mpfr_ptr, mp_prec_t)); +void mpfr_set_default_prec _PROTO((mp_prec_t)); +extern mp_prec_t __gmp_default_fp_bit_precision; +extern mp_rnd_t __gmp_default_rounding_mode; +char * mpfr_print_rnd_mode _PROTO((mp_rnd_t)); +void mpfr_neg _PROTO((mpfr_ptr, mpfr_srcptr, mp_rnd_t)); +void mpfr_sub_one_ulp _PROTO((mpfr_ptr)); +int mpfr_div_ui _PROTO((mpfr_ptr, mpfr_srcptr, unsigned long int, mp_rnd_t)); +void mpfr_ui_div _PROTO((mpfr_ptr, unsigned long int, mpfr_srcptr, mp_rnd_t)); +mp_prec_t mpfr_get_prec _PROTO((mpfr_srcptr)); +void mpfr_set_default_rounding_mode _PROTO((mp_rnd_t)); +int mpfr_eq _PROTO((mpfr_srcptr, mpfr_srcptr, unsigned long)); +void mpfr_floor _PROTO((mpfr_ptr, mpfr_srcptr)); +void mpfr_trunc _PROTO((mpfr_ptr, mpfr_srcptr)); +void mpfr_ceil _PROTO((mpfr_ptr, mpfr_srcptr)); +void mpfr_extract _PROTO((mpz_ptr, mpfr_srcptr, unsigned int)); +void mpfr_swap _PROTO((mpfr_ptr, mpfr_ptr)); +void mpfr_dump _PROTO((mpfr_srcptr, mp_rnd_t)); +void mpfr_set4 _PROTO ((mpfr_ptr, mpfr_srcptr, mp_rnd_t, int)); +int mpfr_cmp3 _PROTO ((mpfr_srcptr, mpfr_srcptr, long int)); +#if defined (__cplusplus) +} +#endif + +#define mpfr_cmp_ui(b,i) mpfr_cmp_ui_2exp((b),(i),0) +#define mpfr_cmp_si(b,i) mpfr_cmp_si_2exp((b),(i),0) +#define mpfr_set(a,b,r) mpfr_set4(a,b,r,MPFR_SIGN(b)) +#define mpfr_abs(a,b,r) mpfr_set4(a,b,r,1) +#define mpfr_cmp(b, c) mpfr_cmp3(b, c, 1) + +#define mpfr_init_set_si(x, i, rnd) \ + do { mpfr_init(x); mpfr_set_si((x), (i), (rnd)); } while (0) +#define mpfr_init_set_ui(x, i, rnd) \ + do { mpfr_init(x); mpfr_set_ui((x), (i), (rnd)); } while (0) +#define mpfr_init_set_d(x, d, rnd) \ + do { mpfr_init(x); mpfr_set_d((x), (d), (rnd)); } while (0) +#define mpfr_init_set(x, y, rnd) \ + do { mpfr_init(x); mpfr_set((x), (y), (rnd)); } while (0) +#define mpfr_init_set_f(x, y, rnd) \ + do { mpfr_init(x); mpfr_set_f((x), (y), (rnd)); } while (0) diff --git a/mpfr/mpz_set_fr.c b/mpfr/mpz_set_fr.c new file mode 100644 index 000000000..92f14f17d --- /dev/null +++ b/mpfr/mpz_set_fr.c @@ -0,0 +1,63 @@ +/* mpz_set_fr -- set a multiple-precision integer from a floating-point number + +Copyright (C) 2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" +#include "gmp-impl.h" +#include "longlong.h" + +/* puts the mantissa of f into z, and returns 'exp' such that f = z * 2^exp + */ +mp_exp_t +#if __STDC__ +mpz_set_fr (mpz_ptr z, mpfr_srcptr f) +#else +mpz_set_fr (z, f) + mpz_ptr z; + mpfr_srcptr f; +#endif +{ + int fn, sh; + + /* TODO: semantique de INF, NAN dans ce contexte ; lever une FPE ? */ + + fn = 1 + (MPFR_PREC(f)-1)/BITS_PER_MP_LIMB; + + /* check whether allocated space for z is enough */ + if (ALLOC(z) < fn) { + PTR(z) = (mp_ptr) (*_mp_reallocate_func) (PTR(z), + ABS(SIZ(z))*BYTES_PER_MP_LIMB, fn*BYTES_PER_MP_LIMB); + if (PTR(z) == NULL) { + fprintf (stderr, "Error in mpz_set_fr: no more memory available\n"); + exit (1); + } + ALLOC(z) = fn; + } + + sh = fn*BITS_PER_MP_LIMB - MPFR_PREC(f); + if (sh) mpn_rshift(PTR(z), MPFR_MANT(f), fn, sh); + else MPN_COPY(PTR(z), MPFR_MANT(f), fn); + + SIZ(z) = fn; + + return MPFR_EXP(f)-MPFR_PREC(f); +} diff --git a/mpfr/mul.c b/mpfr/mul.c index c7c3cd3f5..945bd35ec 100644 --- a/mpfr/mul.c +++ b/mpfr/mul.c @@ -1,6 +1,6 @@ /* mpfr_mul -- multiply two floating-point numbers -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -23,36 +23,61 @@ MA 02111-1307, USA. */ #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" /* Remains to do: -- do not use all bits of b and c when PREC(b)>PREC(a) or PREC(c)>PREC(a) - [current complexity is O(PREC(b)*PREC(c))] +- do not use all bits of b and c when MPFR_PREC(b)>MPFR_PREC(a) or MPFR_PREC(c)>MPFR_PREC(a) + [current complexity is O(MPFR_PREC(b)*MPFR_PREC(c))] */ void #if __STDC__ -mpfr_mul(mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, unsigned char rnd_mode) +mpfr_mul(mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mp_rnd_t rnd_mode) #else mpfr_mul(a, b, c, rnd_mode) - mpfr_ptr a; - mpfr_srcptr b; - mpfr_srcptr c; - unsigned char rnd_mode; + mpfr_ptr a; + mpfr_srcptr b; + mpfr_srcptr c; + mp_rnd_t rnd_mode; #endif { unsigned int bn, cn, an, tn, k; int cc; - mp_limb_t *ap=MANT(a), *bp=MANT(b), *cp=MANT(c), *tmp, b1; + mp_limb_t *ap=MPFR_MANT(a), *bp=MPFR_MANT(b), *cp=MPFR_MANT(c), *tmp, b1; long int sign_product; TMP_DECL(marker); /* deal with NaN and zero */ - if (FLAG_NAN(b) || FLAG_NAN(c)) { SET_NAN(a); return; } - if (!NOTZERO(b) || !NOTZERO(c)) { SET_ZERO(a); return; } + if (MPFR_IS_NAN(b) || MPFR_IS_NAN(c)) + { MPFR_CLEAR_FLAGS(a); MPFR_SET_NAN(a); return; } + if (MPFR_IS_INF(b)) + { + if (!MPFR_NOTZERO(c)) { MPFR_CLEAR_FLAGS(a); MPFR_SET_NAN(a); return; } + else + { + if (MPFR_SIGN(a) != MPFR_SIGN(b) * MPFR_SIGN(c)) MPFR_CHANGE_SIGN(a); + MPFR_CLEAR_FLAGS(a); + MPFR_SET_INF(a); return; + } + } + else if (MPFR_IS_INF(c)) + { + if (!MPFR_NOTZERO(b)) { MPFR_CLEAR_FLAGS(a); MPFR_SET_NAN(a); return; } + else + { + if (MPFR_SIGN(a) != MPFR_SIGN(b) * MPFR_SIGN(c)) MPFR_CHANGE_SIGN(a); + MPFR_CLEAR_FLAGS(a); MPFR_SET_INF(a); return; + } + } - sign_product = SIGN(b) * SIGN(c); - bn = (PREC(b)-1)/mp_bits_per_limb+1; /* number of significant limbs of b */ - cn = (PREC(c)-1)/mp_bits_per_limb+1; /* number of significant limbs of c */ - tn = (PREC(c)+PREC(b)-1)/mp_bits_per_limb+1; + if (!MPFR_NOTZERO(b) || !MPFR_NOTZERO(c)) + { MPFR_CLEAR_FLAGS(a); MPFR_SET_ZERO(a); return; } + + sign_product = MPFR_SIGN(b) * MPFR_SIGN(c); + + MPFR_CLEAR_FLAGS(a); + bn = (MPFR_PREC(b)-1)/BITS_PER_MP_LIMB+1; /* number of significant limbs of b */ + cn = (MPFR_PREC(c)-1)/BITS_PER_MP_LIMB+1; /* number of significant limbs of c */ + tn = (MPFR_PREC(c)+MPFR_PREC(b)-1)/BITS_PER_MP_LIMB+1; k = bn+cn; /* effective nb of limbs used by b*c */ TMP_MARK(marker); tmp = (mp_limb_t*) TMP_ALLOC(k*BYTES_PER_MP_LIMB); @@ -61,18 +86,18 @@ mpfr_mul(a, b, c, rnd_mode) b1 = (bn>=cn) ? mpn_mul(tmp, bp, bn, cp, cn) : mpn_mul(tmp, cp, cn, bp, bn); /* now tmp[0]..tmp[k-1] contains the product of both mantissa, - with tmp[k-1]>=2^(mp_bits_per_limb-2) */ - an = (PREC(a)-1)/mp_bits_per_limb+1; /* number of significant limbs of a */ - b1 >>= mp_bits_per_limb-1; /* msb from the product */ + with tmp[k-1]>=2^(BITS_PER_MP_LIMB-2) */ + an = (MPFR_PREC(a)-1)/BITS_PER_MP_LIMB+1; /* number of significant limbs of a */ + b1 >>= BITS_PER_MP_LIMB-1; /* msb from the product */ if (b1==0) mpn_lshift(tmp, tmp, k, 1); cc = mpfr_round_raw(ap, tmp+bn+cn-tn, - PREC(b)+PREC(c), (sign_product<0), PREC(a), rnd_mode); + MPFR_PREC(b)+MPFR_PREC(c), (sign_product<0), MPFR_PREC(a), rnd_mode); if (cc) { /* cc = 1 ==> result is a power of two */ ap[an-1] = (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); } - EXP(a) = EXP(b) + EXP(c) + b1 - 1 + cc; - if (sign_product * SIGN(a)<0) CHANGE_SIGN(a); + MPFR_EXP(a) = MPFR_EXP(b) + MPFR_EXP(c) + b1 - 1 + cc; + if (sign_product * MPFR_SIGN(a)<0) MPFR_CHANGE_SIGN(a); TMP_FREE(marker); return; } diff --git a/mpfr/mul_2exp.c b/mpfr/mul_2exp.c index 31dab2ac6..e1d030751 100644 --- a/mpfr/mul_2exp.c +++ b/mpfr/mul_2exp.c @@ -1,6 +1,6 @@ /* mpfr_mul_2exp -- multiply a floating-point number by a power of two -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -23,21 +23,22 @@ MA 02111-1307, USA. */ #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" void #if __STDC__ -mpfr_mul_2exp(mpfr_ptr y, mpfr_srcptr x, unsigned long int n, unsigned char rnd_mode) +mpfr_mul_2exp(mpfr_ptr y, mpfr_srcptr x, unsigned long int n, mp_rnd_t rnd_mode) #else mpfr_mul_2exp(y, x, n, rnd_mode) mpfr_ptr y; mpfr_srcptr x; - unsigned long int n; - unsigned char rnd_mode; + unsigned long int n; + mp_rnd_t rnd_mode; #endif { /* Important particular case */ if (y != x) mpfr_set(y, x, rnd_mode); - EXP(y) += n; + MPFR_EXP(y) += n; return; } diff --git a/mpfr/mul_ui.c b/mpfr/mul_ui.c index 83981a83c..e92a79155 100644 --- a/mpfr/mul_ui.c +++ b/mpfr/mul_ui.c @@ -1,6 +1,6 @@ /* mpfr_mul_ui -- multiply a floating-point number by a machine integer -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -24,46 +24,96 @@ MA 02111-1307, USA. */ #include "gmp-impl.h" #include "longlong.h" #include "mpfr.h" +#include "mpfr-impl.h" void #if __STDC__ -mpfr_mul_ui(mpfr_ptr y, mpfr_srcptr x, unsigned long u, unsigned char RND_MODE) +mpfr_mul_ui(mpfr_ptr y, mpfr_srcptr x, unsigned long int u, mp_rnd_t rnd_mode) #else -mpfr_mul_ui(y, x, u, RND_MODE) - mpfr_ptr y; - mpfr_srcptr x; - unsigned long u; - unsigned char RND_MODE; +mpfr_mul_ui(y, x, u, rnd_mode) + mpfr_ptr y; + mpfr_srcptr x; + unsigned long int u; + mp_rnd_t rnd_mode; #endif { - mp_limb_t carry, *my, *old_my; unsigned long c; - unsigned long xsize, ysize, cnt, dif; + mp_limb_t carry, *my, *old_my, *my2; unsigned long c; + unsigned long xsize, ysize, cnt, dif, ex, sh; TMP_DECL(marker); + if (MPFR_IS_NAN(x)) + { + MPFR_CLEAR_FLAGS(y); + MPFR_SET_NAN(y); + return; + } + + if (MPFR_IS_INF(x)) + { + MPFR_CLEAR_FLAGS(y); + if (u) + { + MPFR_SET_INF(y); + if (MPFR_SIGN(y) != MPFR_SIGN(x)) { MPFR_CHANGE_SIGN(y); } + return; + } + else { MPFR_SET_NAN(y); return; } + } + + MPFR_CLEAR_FLAGS(y); + TMP_MARK(marker); - my = MANT(y); - ysize = (PREC(y)-1)/BITS_PER_MP_LIMB + 1; - xsize = (PREC(x)-1)/BITS_PER_MP_LIMB + 1; + my = MPFR_MANT(y); ex = MPFR_EXP(x); + ysize = (MPFR_PREC(y)-1)/BITS_PER_MP_LIMB + 1; + xsize = (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB + 1; + + old_my = my; if (ysize < xsize) { - old_my = my; my = (mp_ptr) TMP_ALLOC (xsize * BYTES_PER_MP_LIMB); dif=0; } else dif=ysize-xsize; - carry = mpn_mul_1(my+dif, MANT(x), xsize, u); + carry = mpn_mul_1(my+dif, MPFR_MANT(x), xsize, u); MPN_ZERO(my, dif); /* WARNING: count_leading_zeros is undefined for carry=0 */ if (carry) count_leading_zeros(cnt, carry); else cnt=BITS_PER_MP_LIMB; - - c = mpfr_round_raw(my, my, PREC(x), (SIGN(x)<0), - PREC(y)-BITS_PER_MP_LIMB+cnt, RND_MODE); - + + /* Warning: the number of limbs used by x and the lower part + of y may differ */ + sh = (MPFR_PREC(x)+BITS_PER_MP_LIMB-1)/BITS_PER_MP_LIMB + - (MPFR_PREC(y)+cnt-1)/BITS_PER_MP_LIMB; + + /* Warning: if all significant bits are in the carry, one has to + be careful */ + if (cnt + MPFR_PREC(y) < BITS_PER_MP_LIMB) + { + /* Quick 'n dirty */ + + if (xsize > ysize) { + my2 = (mp_ptr) TMP_ALLOC ((xsize + 1) * BYTES_PER_MP_LIMB); + my2[xsize] = mpn_lshift(my2, my, xsize, cnt) + | (carry << (cnt ? BITS_PER_MP_LIMB - cnt : 0)); + } + else { + my2 = (mp_ptr) TMP_ALLOC ((ysize + 1) * BYTES_PER_MP_LIMB); + my2[ysize] = mpn_lshift(my2, my, ysize, cnt) + | (carry << (cnt ? BITS_PER_MP_LIMB - cnt : 0)); + } + + my = my2; ex += BITS_PER_MP_LIMB - cnt; + carry = 0; cnt = BITS_PER_MP_LIMB; + } + + c = mpfr_round_raw(my+sh, my, MPFR_PREC(x), (MPFR_SIGN(x)<0), + MPFR_PREC(y)-BITS_PER_MP_LIMB+cnt, rnd_mode); + /* If cnt = 1111111111111 and c = 1 we shall get depressed */ - if (c && (carry == (((mp_limb_t)1) << (BITS_PER_MP_LIMB - cnt)) - 1)) + if (c && (carry == (((mp_limb_t)1) << (cnt ? BITS_PER_MP_LIMB - cnt : 0)) + - 1)) { cnt--; mpn_rshift(my, my, ysize, BITS_PER_MP_LIMB - cnt); @@ -76,9 +126,9 @@ mpfr_mul_ui(y, x, u, RND_MODE) mpn_rshift(my, my, ysize, BITS_PER_MP_LIMB - cnt); my[ysize - 1] |= (carry << cnt); } - EXP(y) = EXP(x) + BITS_PER_MP_LIMB - cnt; + MPFR_EXP(y) = ex + BITS_PER_MP_LIMB - cnt; if (ysize < xsize) MPN_COPY(old_my, my, ysize); /* set sign */ - if (SIGN(y) != SIGN(x)) CHANGE_SIGN(y); + if (MPFR_SIGN(y) * MPFR_SIGN(x) < 0) MPFR_CHANGE_SIGN(y); TMP_FREE(marker); } diff --git a/mpfr/neg.c b/mpfr/neg.c index fff73a65a..b67e0c9d2 100644 --- a/mpfr/neg.c +++ b/mpfr/neg.c @@ -1,6 +1,6 @@ /* mpfr_neg -- change the sign of a floating-point number -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -21,20 +21,20 @@ MA 02111-1307, USA. */ #include <stdio.h> #include "gmp.h" -#include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" void #if __STDC__ -mpfr_neg(mpfr_ptr a, mpfr_srcptr b, unsigned char rnd_mode) +mpfr_neg (mpfr_ptr a, mpfr_srcptr b, mp_rnd_t rnd_mode) #else -mpfr_neg(a, b, rnd_mode) - mpfr_ptr a; - mpfr_srcptr b; - unsigned char rnd_mode; +mpfr_neg (a, b, rnd_mode) + mpfr_ptr a; + mpfr_srcptr b; + mp_rnd_t rnd_mode; #endif { - if (a != b) mpfr_set4(a, b, rnd_mode, -SIGN(b)); - else CHANGE_SIGN(a); + if (a != b) mpfr_set4(a, b, rnd_mode, -MPFR_SIGN(b)); + else MPFR_CHANGE_SIGN(a); return; } diff --git a/mpfr/out_str.c b/mpfr/out_str.c index d6221776b..9b7d7408b 100644 --- a/mpfr/out_str.c +++ b/mpfr/out_str.c @@ -1,6 +1,6 @@ /* mpfr_out_str -- output a floating-point number to a stream -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -20,30 +20,37 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <stdio.h> -#include <math.h> +#include <string.h> #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" size_t #if __STDC__ mpfr_out_str (FILE *stream, int base, size_t n_digits, mpfr_srcptr op, - unsigned char rnd_mode) + mp_rnd_t rnd_mode) #else mpfr_out_str (stream, base, n_digits, op, rnd_mode) - FILE *stream; + FILE *stream; int base; - size_t n_digits; - mpfr_srcptr op; - unsigned char rnd_mode; + size_t n_digits; + mpfr_srcptr op; + mp_rnd_t rnd_mode; #endif { char *s,*s0; size_t l; mp_exp_t e; - if (FLAG_NAN(op)) { fprintf(stream, "NaN"); return 3; } - if (!NOTZERO(op)) { fprintf(stream, "0"); return 1; } + if (MPFR_IS_NAN(op)) { fprintf(stream, "NaN"); return 3; } + if (!MPFR_NOTZERO(op)) { fprintf(stream, "0"); return 1; } + if (MPFR_IS_INF(op)) + { + if (MPFR_SIGN(op) == 1) { fprintf(stream, "Inf"); return 3; } + else { fprintf(stream, "-Inf"); return 4; } + } s = mpfr_get_str(NULL, &e, base, n_digits, op, rnd_mode); + /* TODO: maintenir le code pour les infinis dans get_str ? */ s0 = s; /* for op=3.1416 we have s = "31416" and e = 1 */ @@ -60,6 +67,6 @@ mpfr_out_str (stream, base, n_digits, op, rnd_mode) fprintf(stream, "%s", s); } - (*__gmp_free_func)(s0, l); + (*_mp_free_func)(s0, l); return l; } @@ -1,6 +1,6 @@ -/* mpfr_pi -- compute Pi +/* mpfr_const_pi -- compute Pi -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -20,14 +20,111 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <stdio.h> -#include <math.h> #include "gmp.h" #include "gmp-impl.h" #include "longlong.h" #include "mpfr.h" +#include "mpfr-impl.h" + +int mpfr_aux_pi (mpfr_ptr, mpz_srcptr, int, int); +int mpfr_pi_machin3 (mpfr_ptr, mp_rnd_t); + +#define A +#define A1 1 +#define A2 2 +#undef B +#define C +#define C1 3 +#define C2 2 +#define GENERIC mpfr_aux_pi +#define R_IS_RATIONAL +#define NO_FACTORIAL +#include "generic.c" + + +int +#if __STDC__ +mpfr_pi_machin3 (mpfr_ptr mylog, mp_rnd_t rnd_mode) +#else +mpfr_pi_machin3 (mylog, rnd_mode) + mpfr_ptr mylog; + mp_rnd_t rnd_mode; +#endif +{ + int prec, logn, prec_x; + int prec_i_want=MPFR_PREC(mylog); + int good = 0; + mpfr_t tmp1, tmp2, result,tmp3,tmp4,tmp5,tmp6; + mpz_t cst; + + MPFR_CLEAR_FLAGS(mylog); + logn = _mpfr_ceil_log2 ((double) MPFR_PREC(mylog)); + prec_x = prec_i_want + logn + 5; + mpz_init(cst); + while (!good){ + prec = _mpfr_ceil_log2 ((double) prec_x); + + mpfr_init2(tmp1, prec_x); + mpfr_init2(tmp2, prec_x); + mpfr_init2(tmp3, prec_x); + mpfr_init2(tmp4, prec_x); + mpfr_init2(tmp5, prec_x); + mpfr_init2(tmp6, prec_x); + mpfr_init2(result, prec_x); + mpz_set_si(cst, -1); + + mpfr_aux_pi(tmp1, cst, 268*268, prec - 4); + mpfr_div_ui(tmp1, tmp1, 268, GMP_RNDD); + mpfr_mul_ui(tmp1, tmp1, 61, GMP_RNDD); + + mpfr_aux_pi(tmp2, cst, 343*343, prec - 4); + mpfr_div_ui(tmp2, tmp2, 343, GMP_RNDD); + mpfr_mul_ui(tmp2, tmp2, 122, GMP_RNDD); + + mpfr_aux_pi(tmp3, cst, 557*557, prec - 4); + mpfr_div_ui(tmp3, tmp3, 557, GMP_RNDD); + mpfr_mul_ui(tmp3, tmp3, 115, GMP_RNDD); + + mpfr_aux_pi(tmp4, cst, 1068*1068, prec - 4); + mpfr_div_ui(tmp4, tmp4, 1068, GMP_RNDD); + mpfr_mul_ui(tmp4, tmp4, 32, GMP_RNDD); + + mpfr_aux_pi(tmp5, cst, 3458*3458, prec - 4); + mpfr_div_ui(tmp5, tmp5, 3458, GMP_RNDD); + mpfr_mul_ui(tmp5, tmp5, 83, GMP_RNDD); + + mpfr_aux_pi(tmp6, cst, 27493*27493, prec - 4); + mpfr_div_ui(tmp6, tmp6, 27493, GMP_RNDD); + mpfr_mul_ui(tmp6, tmp6, 44, GMP_RNDD); + + mpfr_add(result, tmp1, tmp2, GMP_RNDD); + mpfr_add(result, result, tmp3, GMP_RNDD); + mpfr_sub(result, result, tmp4, GMP_RNDD); + mpfr_add(result, result, tmp5, GMP_RNDD); + mpfr_add(result, result, tmp6, GMP_RNDD); + mpfr_mul_2exp(result, result, 2, GMP_RNDD); + mpfr_clear(tmp1); + mpfr_clear(tmp2); + mpfr_clear(tmp3); + mpfr_clear(tmp4); + mpfr_clear(tmp5); + mpfr_clear(tmp6); + if (mpfr_can_round(result, prec_x - 5, GMP_RNDD, rnd_mode, prec_i_want)){ + mpfr_set(mylog, result, rnd_mode); + mpfr_clear(result); + good = 1; + } else + { + mpfr_clear(result); + prec_x += logn; + } + } + mpz_clear(cst); + return 0; +} /* -Set x to the value of Pi to precision PREC(x) rounded to direction rnd_mode. +Set x to the value of Pi to precision MPFR_PREC(x) rounded to direction rnd_mode. Use the formula giving the binary representation of Pi found by Simon Plouffe and the Borwein's brothers: @@ -56,76 +153,79 @@ S(N)-S'(N) <= sum(1, n=0..N-1) = N so Pi*16^N-S'(N) <= N+1 (as 1/4/N^2 < 1) */ -mpfr_t __mpfr_pi; /* stored value of Pi */ -int __mpfr_pi_prec=0; /* precision of stored value */ -char __mpfr_pi_rnd; /* rounding mode of stored value */ +mpfr_t __mpfr_const_pi; /* stored value of Pi */ +int __mpfr_const_pi_prec=0; /* precision of stored value */ +mp_rnd_t __mpfr_const_pi_rnd; /* rounding mode of stored value */ void #if __STDC__ -mpfr_pi(mpfr_ptr x, unsigned char rnd_mode) +mpfr_const_pi(mpfr_ptr x, mp_rnd_t rnd_mode) #else -mpfr_pi(x, rnd_mode) - mpfr_ptr x; - unsigned char rnd_mode; +mpfr_const_pi(x, rnd_mode) + mpfr_ptr x; + mp_rnd_t rnd_mode; #endif { int N, oldN, n, prec; mpz_t pi, num, den, d3, d2, tmp; mpfr_t y; - prec=PREC(x); + prec=MPFR_PREC(x); /* has stored value enough precision ? */ - if ((prec==__mpfr_pi_prec && rnd_mode==__mpfr_pi_rnd) || - (prec<=__mpfr_pi_prec && - mpfr_can_round(__mpfr_pi, __mpfr_pi_prec, __mpfr_pi_rnd, rnd_mode, prec))) + if ((prec==__mpfr_const_pi_prec && rnd_mode==__mpfr_const_pi_rnd) || + (prec<=__mpfr_const_pi_prec && + mpfr_can_round(__mpfr_const_pi, __mpfr_const_pi_prec, + __mpfr_const_pi_rnd, rnd_mode, prec))) { - mpfr_set(x, __mpfr_pi, rnd_mode); return; + mpfr_set(x, __mpfr_const_pi, rnd_mode); return; } - /* need to recompute */ - N=1; - do { - oldN = N; - N = (prec+3)/4 + (int)ceil(log((double)N+1.0)/log(2.0)); - } while (N != oldN); - mpz_init(pi); mpz_init(num); mpz_init(den); mpz_init(d3); mpz_init(d2); - mpz_init(tmp); - mpz_set_ui(pi, 0); - mpz_set_ui(num, 16); /* num(-1) */ - mpz_set_ui(den, 21); /* den(-1) */ - mpz_set_si(d3, -2454); - mpz_set_ui(d2, 14736); + if (prec < 20000){ + /* need to recompute */ + N=1; + do { + oldN = N; + N = (prec+3)/4 + _mpfr_ceil_log2((double) N + 1.0); + } while (N != oldN); + mpz_init(pi); mpz_init(num); mpz_init(den); mpz_init(d3); mpz_init(d2); + mpz_init(tmp); + mpz_set_ui(pi, 0); + mpz_set_ui(num, 16); /* num(-1) */ + mpz_set_ui(den, 21); /* den(-1) */ + mpz_set_si(d3, -2454); + mpz_set_ui(d2, 14736); /* invariants: num=120*n^2+151*n+47, den=512*n^4+1024*n^3+712*n^2+194*n+15 - d3 = 2048*n^3+400*n-6, d2 = 6144*n^2-6144*n+2448 + d3 = 2048*n^3+400*n-6, d2 = 6144*n^2-6144*n+2448 */ - for (n=0; n<N; n++) { - /* num(n)-num(n-1) = 240*n+31 */ - mpz_add_ui(num, num, 240*n+31); /* no overflow up to PREC=71M */ - /* d2(n) - d2(n-1) = 12288*(n-1) */ - if (n>0) mpz_add_ui(d2, d2, 12288*(n-1)); - else mpz_sub_ui(d2, d2, 12288); - /* d3(n) - d3(n-1) = d2 */ - mpz_add(d3, d3, d2); - /* den(n)-den(n-1) = 2048*n^3 + 400n - 6 = d3 */ - mpz_add(den, den, d3); - mpz_mul_2exp(tmp, num, 4*(N-n)); - mpz_fdiv_q(tmp, tmp, den); - mpz_add(pi, pi, tmp); - } - mpfr_set_z(x, pi, rnd_mode); - mpfr_init2(y, mpfr_get_prec(x)); - mpz_add_ui(pi, pi, N+1); - mpfr_set_z(y, pi, rnd_mode); - if (mpfr_cmp(x, y) != 0) { - fprintf(stderr, "does not converge\n"); exit(1); - } - EXP(x) -= 4*N; - mpz_clear(pi); mpz_clear(num); mpz_clear(den); mpz_clear(d3); mpz_clear(d2); - mpz_clear(tmp); mpfr_clear(y); - + for (n=0; n<N; n++) { + /* num(n)-num(n-1) = 240*n+31 */ + mpz_add_ui(num, num, 240*n+31); /* no overflow up to MPFR_PREC=71M */ + /* d2(n) - d2(n-1) = 12288*(n-1) */ + if (n>0) mpz_add_ui(d2, d2, 12288*(n-1)); + else mpz_sub_ui(d2, d2, 12288); + /* d3(n) - d3(n-1) = d2 */ + mpz_add(d3, d3, d2); + /* den(n)-den(n-1) = 2048*n^3 + 400n - 6 = d3 */ + mpz_add(den, den, d3); + mpz_mul_2exp(tmp, num, 4*(N-n)); + mpz_fdiv_q(tmp, tmp, den); + mpz_add(pi, pi, tmp); + } + mpfr_set_z(x, pi, rnd_mode); + mpfr_init2(y, mpfr_get_prec(x)); + mpz_add_ui(pi, pi, N+1); + mpfr_set_z(y, pi, rnd_mode); + if (mpfr_cmp(x, y) != 0) { + fprintf(stderr, "does not converge\n"); exit(1); + } + MPFR_EXP(x) -= 4*N; + mpz_clear(pi); mpz_clear(num); mpz_clear(den); mpz_clear(d3); mpz_clear(d2); + mpz_clear(tmp); mpfr_clear(y); + } else + mpfr_pi_machin3(x, rnd_mode); /* store computed value */ - if (__mpfr_pi_prec==0) mpfr_init2(__mpfr_pi, prec); - else mpfr_set_prec(__mpfr_pi, prec); - mpfr_set(__mpfr_pi, x, rnd_mode); - __mpfr_pi_prec=prec; - __mpfr_pi_rnd=rnd_mode; + if (__mpfr_const_pi_prec==0) mpfr_init2(__mpfr_const_pi, prec); + else mpfr_set_prec(__mpfr_const_pi, prec); + mpfr_set(__mpfr_const_pi, x, rnd_mode); + __mpfr_const_pi_prec=prec; + __mpfr_const_pi_rnd=rnd_mode; } diff --git a/mpfr/pow.c b/mpfr/pow.c index c53819ec2..3032c5d72 100644 --- a/mpfr/pow.c +++ b/mpfr/pow.c @@ -1,7 +1,7 @@ /* mpfr_pow_ui, mpfr_ui_pow_ui -- compute the power of a floating-point number or machine integer -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -23,45 +23,99 @@ MA 02111-1307, USA. */ #include <stdio.h> #include "gmp.h" #include "mpfr.h" +#include "mpfr-impl.h" -/* sets x to y^n */ -void +/* sets x to y^n, and returns ceil(log2(max ulp error)) */ +int #if __STDC__ -mpfr_pow_ui (mpfr_ptr x, mpfr_srcptr y, unsigned int n, unsigned char rnd) +mpfr_pow_ui (mpfr_ptr x, mpfr_srcptr y, unsigned long int n, mp_rnd_t rnd) #else mpfr_pow_ui (x, y, n, rnd) mpfr_ptr x; - mpfr_srcptr y; - unsigned int n; - unsigned char rnd; + mpfr_srcptr y; + unsigned long int n; + mp_rnd_t rnd; #endif { - int i; + long int i; + unsigned long m; + double err; + mpfr_t ycopy; + + if (MPFR_IS_NAN(y)) { MPFR_SET_NAN(x); return 0; } + + MPFR_CLEAR_NAN(x); + + if (MPFR_IS_INF(y)) + { + if (n == 0) { MPFR_SET_NAN(x); return 0; } + /* Inf^n = Inf, (-Inf)^n = Inf for n even, -Inf for n odd */ + else if ((MPFR_SIGN(y) < 0) && (n % 2 == 1)) { + if (MPFR_SIGN(x) > 0) MPFR_CHANGE_SIGN(x); + } + else if (MPFR_SIGN(x) < 0) + MPFR_CHANGE_SIGN(x); + MPFR_SET_INF(x); return 0; + } - if (n==0) { mpfr_set_ui(x, 1, rnd); return; } + MPFR_CLEAR_INF(x); + + if (n==0) { mpfr_set_ui(x, 1, rnd); return 0; } + + if (x == y) { + mpfr_init2 (ycopy, MPFR_PREC(y)); + mpfr_set (ycopy, y, GMP_RNDN); /* exact */ + } + mpfr_set(x, y, rnd); - for (i=0;(1<<i)<=n;i++); + err = 1.0; + for (m=n, i=0; m; i++, m>>=1); /* now 2^(i-1) <= n < 2^i */ for (i-=2; i>=0; i--) { - mpfr_mul(x, x, x, rnd); - if (n & (1<<i)) mpfr_mul(x, x, y, rnd); + mpfr_mul(x, x, x, rnd); err = 2.0*err+1.0; + if (n & (1<<i)) { + mpfr_mul(x, x, (x == y) ? ycopy : y, rnd); + err += 1.0; + } } - return; + + if (x == y) mpfr_clear (ycopy); + return _mpfr_ceil_log2 (err); } -/* sets x to y^n */ -void mpfr_ui_pow_ui (mpfr_ptr x, unsigned int y, unsigned int n, - unsigned char rnd) +/* sets x to y^n, and returns ceil(log2(max ulp error)) */ + +/* TODO: gerer l'infini en cas de debordement ? Fait mecaniquement si fait + dans mul ? */ + +int +#if __STDC__ +mpfr_ui_pow_ui (mpfr_ptr x, unsigned long int y, unsigned long int n, + mp_rnd_t rnd) +#else +mpfr_ui_pow_ui (x, y, n, rnd) + mpfr_ptr x; + unsigned long int y; + unsigned long int n; + mp_rnd_t rnd; +#endif { - int i; + long int i; double err; + + MPFR_CLEAR_FLAGS(x); + if (n==0) { mpfr_set_ui(x, 1, rnd); return 0; } - if (n==0) { mpfr_set_ui(x, 1, rnd); return; } mpfr_set_ui(x, y, rnd); + err = 1.0; + for (i=0;(1<<i)<=n;i++); /* now 2^(i-1) <= n < 2^i */ for (i-=2; i>=0; i--) { - mpfr_mul(x, x, x, rnd); - if (n & (1<<i)) mpfr_mul_ui(x, x, y, rnd); + mpfr_mul(x, x, x, rnd); err = 2.0 * err + 1.0; + if (n & (1<<i)) { + mpfr_mul_ui(x, x, y, rnd); + err = err + 1.0; + } } - return; + return _mpfr_ceil_log2 (err); } diff --git a/mpfr/print_raw.c b/mpfr/print_raw.c index 4ff68bcaf..69e682757 100644 --- a/mpfr/print_raw.c +++ b/mpfr/print_raw.c @@ -1,7 +1,7 @@ /* mpfr_print_raw -- print the internal binary representation of a floating-point number -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -24,26 +24,31 @@ MA 02111-1307, USA. */ #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" + +void mpfr_get_str_raw (char *, mpfr_srcptr); void #if __STDC__ -mpfr_get_str_raw(char *digit_ptr, mpfr_srcptr x) +mpfr_get_str_raw (char *digit_ptr, mpfr_srcptr x) #else -mpfr_get_str_raw(digit_ptr, x) +mpfr_get_str_raw (digit_ptr, x) char *digit_ptr; mpfr_srcptr x; #endif { mp_limb_t *mx, wd, t; long ex, sx, k, l, p; - mx = MANT(x); - ex = EXP(x); - p = PREC(x); + mx = MPFR_MANT(x); + ex = MPFR_EXP(x); + p = MPFR_PREC(x); + + /* TODO: utilite de gerer l'infini a ce niveau ? */ - if (SIGN(x) < 0) { *digit_ptr = '-'; digit_ptr++; } + if (MPFR_SIGN(x) < 0) { *digit_ptr = '-'; digit_ptr++; } sprintf(digit_ptr, "0."); digit_ptr += 2; - sx = 1+(p-1)/mp_bits_per_limb; /* number of significant limbs */ + sx = 1+(p-1)/BITS_PER_MP_LIMB; /* number of significant limbs */ for (k = sx - 1; k >= 0 ; k--) { wd = mx[k]; @@ -69,23 +74,35 @@ mpfr_print_raw(x) mpfr_srcptr x; #endif { - char *str; + char *str; + unsigned long alloc_size; - if (FLAG_NAN(x)) printf("NaN"); - else if (!NOTZERO(x)) printf("0"); + if (MPFR_IS_NAN(x)) printf("NaN"); + else if (MPFR_IS_INF(x)) { + if (MPFR_SIGN(x) == 1) { printf("Inf"); } else printf("-Inf"); + } + else if (!MPFR_NOTZERO(x)) { + if (MPFR_SIGN(x) < 0) printf("-"); + printf("0"); + } else { /* 3 char for sign + 0 + binary point - + ABSSIZE(x) * BITS_PER_MP_LIMB for mantissa + + MPFR_ABSSIZE(x) * BITS_PER_MP_LIMB for mantissa + 2 for brackets in mantissa + 1 for 'E' + 11 for exponent (including sign) - = 17 + ABSSIZE(x) * BITS_PER_MP_LIMB + = 17 + MPFR_ABSSIZE(x) * BITS_PER_MP_LIMB */ - str = (char *) malloc((17 + ABSSIZE(x) * BITS_PER_MP_LIMB)*sizeof(char)); + alloc_size = 17 + MPFR_ABSSIZE(x) * BITS_PER_MP_LIMB; + str = (char *) (*_mp_allocate_func) (alloc_size * sizeof(char)); + if (str == NULL) { + fprintf (stderr, "Error in mpfr_print_raw: no more memory available\n"); + exit (1); + } mpfr_get_str_raw(str, x); printf("%s", str); - free(str); + (*_mp_free_func) (str, alloc_size * sizeof(char)); } } diff --git a/mpfr/print_rnd_mode.c b/mpfr/print_rnd_mode.c index a7bc1d06d..e97d74eba 100644 --- a/mpfr/print_rnd_mode.c +++ b/mpfr/print_rnd_mode.c @@ -1,6 +1,6 @@ /* mpfr_print_rnd_mode -- convert a given rounding mode to a string -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -21,15 +21,15 @@ MA 02111-1307, USA. */ #include <stdio.h> #include "gmp.h" -#include "gmp-impl.h" #include "mpfr.h" +#include "gmp-impl.h" char * #if __STDC__ -mpfr_print_rnd_mode(unsigned char rnd_mode) +mpfr_print_rnd_mode(mp_rnd_t rnd_mode) #else mpfr_print_rnd_mode(rnd_mode) - unsigned char rnd_mode; + mp_rnd_t rnd_mode; #endif { switch (rnd_mode) @@ -38,6 +38,6 @@ mpfr_print_rnd_mode(rnd_mode) case GMP_RNDU: return("GMP_RNDU"); case GMP_RNDN: return("GMP_RNDN"); case GMP_RNDZ: return("GMP_RNDZ"); - default: return("unknown rounding mode"); + default: fprintf(stderr, "unknown rounding mode\n"); exit(1); } } diff --git a/mpfr/random.c b/mpfr/random.c index e61ddc0b7..e2a50770b 100644 --- a/mpfr/random.c +++ b/mpfr/random.c @@ -1,6 +1,6 @@ /* mpfr_random -- generate a random floating-point number -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -24,51 +24,47 @@ MA 02111-1307, USA. */ #include "gmp-impl.h" #include "longlong.h" #include "mpfr.h" +#include "mpfr-impl.h" -/* Computes a random mpfr in [0, 1[ with precision PREC */ - -extern long random _PROTO((void)); -extern int srandom _PROTO((unsigned int)); - -/* extracted from GNU mpf */ -#if defined (__hpux) || defined (__alpha) -/* HPUX lacks random(). DEC OSF/1 1.2 random() returns a double. */ -#define random mrand48 -#define srandom srand48 -#endif +/* Computes a random mpfr in [0, 1[ with precision MPFR_PREC */ void #if __STDC__ -mpfr_random(mpfr_ptr x) +mpfr_random (mpfr_ptr x) #else -mpfr_random(x) +mpfr_random (x) mpfr_ptr x; #endif { - mp_limb_t *xp; unsigned long xn, i, cnt, prec=PREC(x); + mp_limb_t *xp; unsigned long xn, cnt, prec = MPFR_PREC(x); - xp = MANT(x); + MPFR_CLEAR_FLAGS(x); + xp = MPFR_MANT(x); xn = (prec-1)/BITS_PER_MP_LIMB + 1; - for (i = 0; i < xn; i++) - { - /* random() c/sh/ould be replaced by a homemade random number generator. - Indeed, if on Linux random is a good RNG, this is definitely not - the case in most Un*xes. */ - xp[i] = random(); - } - - count_leading_zeros(cnt, xp[xn - 1]); - if (cnt) mpn_lshift(xp, xp, xn, cnt); - EXP(x) = -cnt; + mpn_random (xp, xn); + + if (xp[xn - 1] == 0) xp[xn - 1] = 1; + /* since count_leading_zeros doesn't like zeroes */ + + count_leading_zeros (cnt, xp[xn - 1]); + if (cnt) mpn_lshift (xp, xp, xn, cnt); + MPFR_EXP(x) = -cnt; cnt = xn*BITS_PER_MP_LIMB - prec; /* cnt is the number of non significant bits in the low limb */ - xp[0] &= ~((((mp_limb_t)1)<<cnt) - 1); + xp[0] &= ~((((mp_limb_t) 1) << cnt) - 1); } +#if HAVE_SRANDOM void -mpfr_srandom(unsigned long seed) +#if __STDC__ +mpfr_srandom (unsigned long int seed) +#else +mpfr_srandom (seed) + unsigned long int seed; +#endif { - srandom(seed); + srandom (seed); } +#endif diff --git a/mpfr/random2.c b/mpfr/random2.c new file mode 100644 index 000000000..f3384d0f4 --- /dev/null +++ b/mpfr/random2.c @@ -0,0 +1,69 @@ +/* mpf_random2 -- Generate a positive random mpf_t of specified size, with + long runs of consecutive ones and zeros in the binary representation. + Intended for testing of other MP routines. + +Copyright (C) 1995, 1996 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the GNU MP Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +void +#if __STDC__ +mpfr_random2 (mpfr_ptr x, mp_size_t size, mp_exp_t exp) +#else +mpfr_random2 (x, size, exp) + mpfr_ptr x; + mp_size_t size; + mp_exp_t exp; +#endif +{ + mp_size_t xn; + unsigned long cnt; + mp_ptr xp = MPFR_MANT(x), yp[1]; + mp_size_t prec = (MPFR_PREC(x) - 1)/BITS_PER_MP_LIMB; + + MPFR_CLEAR_FLAGS(x); + xn = ABS (size); + if (xn != 0) + { + if (xn > prec + 1) + xn = prec + 1; + + mpn_random2 (xp, xn); + } + + if (exp != 0) { + /* use mpn_random instead of random since that function is not + available on all platforms (for example HPUX, DEC OSF, ...) */ + mpn_random ((mp_limb_t*) yp, 1); + exp = (mp_exp_t) yp[0] % (2 * exp) - exp; + } + + count_leading_zeros(cnt, xp[xn - 1]); + if (cnt) mpn_lshift(xp, xp, xn, cnt); + MPFR_EXP(x) = exp-cnt; + cnt = xn*BITS_PER_MP_LIMB - prec; + /* cnt is the number of non significant bits in the low limb */ + xp[0] &= ~((((mp_limb_t)1)<<cnt) - 1); +} diff --git a/mpfr/reldiff.c b/mpfr/reldiff.c new file mode 100644 index 000000000..ea21a60b1 --- /dev/null +++ b/mpfr/reldiff.c @@ -0,0 +1,76 @@ +/* mpfr_reldiff -- compute relative difference of two floating-point numbers. + +Copyright (C) 2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +/* reldiff(b, c) = abs(b-c)/b */ +void +#if __STDC__ +mpfr_reldiff(mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mp_rnd_t rnd_mode) +#else +mpfr_reldiff(a, b, c, rnd_mode) + mpfr_ptr a; + mpfr_srcptr b; + mpfr_srcptr c; + mp_rnd_t rnd_mode; +#endif +{ + mpfr_t b_copy; + + if (MPFR_IS_NAN(b) || MPFR_IS_NAN(c)) + { MPFR_CLEAR_FLAGS(a); MPFR_SET_NAN(a); return; } + if (MPFR_IS_INF(b)) + { + if (MPFR_IS_INF(c) && (MPFR_SIGN(c) == MPFR_SIGN(b))) + { MPFR_CLEAR_FLAGS(a); MPFR_SET_ZERO(a); return; } + else + { MPFR_CLEAR_FLAGS(a); MPFR_SET_NAN(a); return; } + } + + if (MPFR_IS_INF(c)) + { + MPFR_SET_SAME_SIGN(a, b); + MPFR_CLEAR_FLAGS(a); + MPFR_SET_INF(a); + return; + } + + if (MPFR_IS_ZERO(b)) /* reldiff = abs(c)/c = sign(c) */ + /* TODO: faire preciser la SEMANTIQUE DE CE FOUTOIR. */ + mpfr_set_ui(a, MPFR_SIGN(c), rnd_mode); + else { + if (a == b) { + mpfr_init2 (b_copy, MPFR_PREC(b)); + mpfr_set (b_copy, b, GMP_RNDN); + } + + mpfr_sub(a, b, c, rnd_mode); + mpfr_abs(a, a, rnd_mode); /* for compatibility with MPF */ + mpfr_div(a, a, (a == b) ? b_copy : b, rnd_mode); + + if (a == b) mpfr_clear (b_copy); + } +} + diff --git a/mpfr/rnd_mode.c b/mpfr/rnd_mode.c index 9c37fb4c1..dda40b5b4 100644 --- a/mpfr/rnd_mode.c +++ b/mpfr/rnd_mode.c @@ -1,6 +1,6 @@ /* mpfr_set_machine_rnd_mode -- set the rounding mode for machine floats -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -19,6 +19,7 @@ along with the MPFR Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifdef TEST #include <stdio.h> #include "gmp.h" #include "mpfr.h" @@ -30,24 +31,28 @@ MA 02111-1307, USA. */ #define TOZERO fesetround(FE_TOWARDZERO) #define TOINFP fesetround(FE_UPWARD) #define TOINFM fesetround(FE_DOWNWARD) -#elif IRIX64 +#elif __mips #include <sys/fpu.h> extern int swapRM(); #define TOZERO swapRM(ROUND_TO_ZERO) #define TOINFP swapRM(ROUND_TO_PLUS_INFINITY) #define TONEAREST swapRM(ROUND_TO_NEAREST) #define TOINFM swapRM(ROUND_TO_MINUS_INFINITY) -#elif (defined (solaris) || defined (sun4) || defined(hpux)) +#elif (defined (__sparc__) || defined(hpux) || defined(freebsd)) #ifdef hpux #include <math.h> #else +#ifdef freebsd +#include <floatingpoint.h> +#else #include <ieeefp.h> #endif +#endif #define TOZERO fpsetround(FP_RZ) #define TOINFP fpsetround(FP_RP) #define TONEAREST fpsetround(FP_RN) #define TOINFM fpsetround(FP_RM) -#elif alpha +#elif defined (__alpha) #ifdef __GNUC__ /* GCC patched include files forget to define those... */ #define FP_RND_RZ 0 @@ -61,6 +66,11 @@ extern int swapRM(); #define TONEAREST write_rnd(FP_RND_RN) #define TOINFM write_rnd(FP_RND_RM) #elif AIX +/* those values should be defined in float.h but strangely are not */ +#define FP_RND_RZ 0 +#define FP_RND_RN 1 +#define FP_RND_RP 2 +#define FP_RND_RM 3 #include <float.h> #define TOZERO fp_swap_rnd(FP_RND_RZ) #define TOINFP fp_swap_rnd(FP_RND_RP) @@ -73,6 +83,12 @@ char *out; #define TOINFP ieee_flags("set","direction","positive",&out) #define TONEAREST ieee_flags("set","direction","nearest",&out) #define TOINFM ieee_flags("set","direction","negative",&out) +#elif (defined (__powerpc__) && defined(linux)) +#include <fpu_control.h> +#define TOZERO _FPU_SETCW(_FPU_RC_ZERO) +#define TOINFP _FPU_SETCW(_FPU_RC_UP) +#define TOINFM _FPU_SETCW(_FPU_RC_DOWN) +#define TONEAREST _FPU_SETCW(_FPU_RC_NEAREST) #elif (defined (__i386__) || defined (__i486__) || defined (linux)) #ifdef __CYGWIN32__ /* no fpu_control.h under Cygnus */ #define _FPU_EXTENDED 0x300 @@ -101,10 +117,10 @@ char *out; /* sets the machine rounding mode to the value rnd_mode */ void #if __STDC__ -mpfr_set_machine_rnd_mode(unsigned char rnd_mode) +mpfr_set_machine_rnd_mode(mp_rnd_t rnd_mode) #else mpfr_set_machine_rnd_mode(rnd_mode) - unsigned char rnd_mode; + mp_rnd_t rnd_mode; #endif { switch (rnd_mode) { @@ -112,7 +128,7 @@ mpfr_set_machine_rnd_mode(rnd_mode) case GMP_RNDZ: TOZERO; break; case GMP_RNDU: TOINFP; break; case GMP_RNDD: TOINFM; break; - default: fprintf(stderr,"invalid rounding mode\n"); exit(1); + default: fprintf(stderr, "invalid rounding mode\n"); exit(1); } } - +#endif diff --git a/mpfr/round.c b/mpfr/round.c index 99e0e699b..06de436b9 100644 --- a/mpfr/round.c +++ b/mpfr/round.c @@ -1,7 +1,7 @@ /* mpfr_round_raw2, mpfr_round_raw, mpfr_round, mpfr_can_round, mpfr_can_round_raw -- various rounding functions -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -24,10 +24,7 @@ MA 02111-1307, USA. */ #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" - -#ifdef Exp -#include "longlong.h" -#endif +#include "mpfr-impl.h" /* returns 0 if round(sign*xp[0..xn-1], prec, rnd) = round(sign*xp[0..xn-1], prec, GMP_RNDZ), 1 otherwise, @@ -37,25 +34,28 @@ MA 02111-1307, USA. */ */ int #if __STDC__ -mpfr_round_raw2(mp_limb_t *xp, unsigned long xn, - char neg, char rnd, unsigned long prec) +mpfr_round_raw2(mp_limb_t *xp, mp_prec_t xn, + int neg, mp_rnd_t rnd, mp_prec_t prec) #else mpfr_round_raw2(xp, xn, neg, rnd, prec) mp_limb_t *xp; - unsigned long xn; - char neg; - char rnd; - unsigned long prec; + mp_prec_t xn; + int neg; + mp_rnd_t rnd; + mp_prec_t prec; #endif { - unsigned long nw; long wd; char rw; short l; mp_limb_t mask; + mp_prec_t nw; long wd; char rw; short l; mp_limb_t mask; nw = prec / BITS_PER_MP_LIMB; rw = prec & (BITS_PER_MP_LIMB - 1); if (rw) nw++; if (rnd==GMP_RNDZ || xn<nw || (rnd==GMP_RNDU && neg) || (rnd==GMP_RNDD && neg==0)) return 0; - mask = ~((((mp_limb_t)1)<<(BITS_PER_MP_LIMB - rw)) - 1); + if (rw) + mask = ~((((mp_limb_t)1)<<(BITS_PER_MP_LIMB - rw)) - 1); + else mask = ~((mp_limb_t)0); + switch (rnd) { case GMP_RNDU: @@ -108,39 +108,36 @@ mpfr_round_raw2(xp, xn, neg, rnd, prec) } /* puts in y the value of xp (with precision xprec and sign 1 if negative=0, - -1 otherwise) rounded to precision yprec and direction RND_MODE + -1 otherwise) rounded to precision yprec and direction rnd_mode Supposes x is not zero nor NaN nor +/- Infinity (i.e. *xp != 0). */ int #if __STDC__ -mpfr_round_raw(mp_limb_t *y, mp_limb_t *xp, unsigned long xprec, char negative, - unsigned long yprec, char RND_MODE) +mpfr_round_raw(mp_limb_t *y, mp_limb_t *xp, mp_prec_t xprec, int negative, + mp_prec_t yprec, mp_rnd_t rnd_mode) #else -mpfr_round_raw(y, xp, xprec, negative, yprec, RND_MODE) +mpfr_round_raw(y, xp, xprec, negative, yprec, rnd_mode) mp_limb_t *y; mp_limb_t *xp; - unsigned long xprec; + mp_prec_t xprec; char negative; - unsigned long yprec; - char RND_MODE; + mp_prec_t yprec; + mp_rnd_t rnd_mode; #endif { - unsigned long nw, xsize; mp_limb_t mask; - char rw, xrw, carry = 0; + mp_prec_t nw, xsize; mp_limb_t mask; + char rw, carry = 0; xsize = (xprec-1)/BITS_PER_MP_LIMB + 1; - xrw = xprec % BITS_PER_MP_LIMB; if (xrw == 0) { xrw = BITS_PER_MP_LIMB; } - -#ifdef Exp - count_leading_zeros(flag, xp[xsize-1]); - yprec += flag; -#endif nw = yprec / BITS_PER_MP_LIMB; rw = yprec & (BITS_PER_MP_LIMB - 1); if (rw) nw++; /* number of words needed to represent x */ - mask = ~((((mp_limb_t)1)<<(BITS_PER_MP_LIMB - rw)) - (mp_limb_t)1); + if (rw) + mask = ~((((mp_limb_t)1)<<(BITS_PER_MP_LIMB - rw)) - (mp_limb_t)1); + else + mask = ~((mp_limb_t)0); /* precision is larger than the size of x. No rounding is necessary. Just add zeroes at the end */ @@ -151,9 +148,15 @@ mpfr_round_raw(y, xp, xprec, negative, yprec, RND_MODE) return 0; } - if (mpfr_round_raw2(xp, xsize, negative, RND_MODE, yprec)) - carry = mpn_add_1(y, xp + xsize - nw, nw, - ((mp_limb_t)1) << (BITS_PER_MP_LIMB - rw)); + if (mpfr_round_raw2(xp, xsize, negative, rnd_mode, yprec)) + { + if (rw) + carry = mpn_add_1(y, xp + xsize - nw, nw, + ((mp_limb_t)1) << (BITS_PER_MP_LIMB - rw)); + else + carry = mpn_add_1(y, xp + xsize - nw, nw, 1); + } + else MPN_COPY(y, xp + xsize - nw, nw); y[0] &= mask; @@ -162,34 +165,50 @@ mpfr_round_raw(y, xp, xprec, negative, yprec, RND_MODE) void #if __STDC__ -mpfr_round(mpfr_t x, char RND_MODE, unsigned long prec) +mpfr_round(mpfr_ptr x, mp_rnd_t rnd_mode, mp_prec_t prec) #else -mpfr_round(x, RND_MODE, prec) - mpfr_t x; - char RND_MODE; - unsigned long prec; +mpfr_round(x, rnd_mode, prec) + mpfr_ptr x; + mp_rnd_t rnd_mode; + mp_prec_t prec; #endif { - mp_limb_t *tmp; int carry; unsigned long nw; - TMP_DECL(marker); + mp_limb_t *tmp; int carry, signx; mp_prec_t nw; + TMP_DECL(marker); + if (MPFR_IS_INF(x) || MPFR_IS_NAN(x)) return; nw = prec / BITS_PER_MP_LIMB; if (prec & (BITS_PER_MP_LIMB - 1)) nw++; + signx = MPFR_SIGN(x); + + /* check if x has enough allocated space for the mantissa */ + if (nw > MPFR_ABSSIZE(x)) { + MPFR_MANT(x) = (mp_ptr) (*_mp_reallocate_func) + (MPFR_MANT(x), MPFR_ABSSIZE(x)*BYTES_PER_MP_LIMB, nw * BYTES_PER_MP_LIMB); + if (MPFR_MANT(x) == NULL) { + fprintf (stderr, "Error in mpfr_round: no more memory available\n"); + exit (1); + } + MPFR_SIZE(x) = nw; /* new number of allocated limbs */ + } + TMP_MARK(marker); tmp = TMP_ALLOC (nw * BYTES_PER_MP_LIMB); - carry = mpfr_round_raw(tmp, MANT(x), PREC(x), (SIGN(x)<0), prec, RND_MODE); + carry = mpfr_round_raw(tmp, MPFR_MANT(x), MPFR_PREC(x), (MPFR_SIGN(x)<0), prec, + rnd_mode); if (carry) { mpn_rshift(tmp, tmp, nw, 1); tmp [nw-1] |= (((mp_limb_t)1) << (BITS_PER_MP_LIMB - 1)); - EXP(x)++; + MPFR_EXP(x)++; } - if (SIGN(x)<0) { SIZE(x)=nw; CHANGE_SIGN(x); } else SIZE(x)=nw; - PREC(x) = prec; - MPN_COPY(MANT(x), tmp, nw); - TMP_FREE(marker); + MPFR_SIZE(x)=nw; + if (signx * MPFR_SIGN(x)<0) MPFR_CHANGE_SIGN(x); + MPFR_PREC(x) = prec; + MPN_COPY(MPFR_MANT(x), tmp, nw); + TMP_FREE(marker); } /* hypotheses : BITS_PER_MP_LIMB est une puissance de 2 @@ -197,7 +216,7 @@ mpfr_round(x, RND_MODE, prec) /* assuming b is an approximation of x in direction rnd1 - with error at most 2^(EXP(b)-err), returns 1 if one is + with error at most 2^(MPFR_EXP(b)-err), returns 1 if one is able to round exactly x to precision prec with direction rnd2, and 0 otherwise. @@ -206,35 +225,34 @@ mpfr_round(x, RND_MODE, prec) int #if __STDC__ -mpfr_can_round(mpfr_t b, unsigned long err, unsigned char rnd1, - unsigned char rnd2, unsigned long prec) +mpfr_can_round(mpfr_ptr b, mp_prec_t err, mp_rnd_t rnd1, + mp_rnd_t rnd2, mp_prec_t prec) #else mpfr_can_round(b, err, rnd1, rnd2, prec) - mpfr_t b; - unsigned long err; - unsigned char rnd1; - unsigned char rnd2; - unsigned long prec; + mpfr_ptr b; + mp_prec_t err; + mp_rnd_t rnd1; + mp_rnd_t rnd2; + mp_prec_t prec; #endif { - return mpfr_can_round_raw(MANT(b), (PREC(b) - 1)/BITS_PER_MP_LIMB + 1, - SIGN(b), err, rnd1, rnd2, prec); + return mpfr_can_round_raw(MPFR_MANT(b), (MPFR_PREC(b) - 1)/BITS_PER_MP_LIMB + 1, + MPFR_SIGN(b), err, rnd1, rnd2, prec); } int #if __STDC__ -mpfr_can_round_raw(mp_limb_t *bp, unsigned long bn, int neg, - unsigned long err, unsigned char rnd1, unsigned char rnd2, - unsigned long prec) +mpfr_can_round_raw(mp_limb_t *bp, mp_prec_t bn, int neg, mp_prec_t err, + mp_rnd_t rnd1, mp_rnd_t rnd2, mp_prec_t prec) #else mpfr_can_round_raw(bp, bn, neg, err, rnd1, rnd2, prec) mp_limb_t *bp; - unsigned long bn; + mp_prec_t bn; int neg; - unsigned long err; - unsigned char rnd1; - unsigned char rnd2; - unsigned long prec; + mp_prec_t err; + mp_rnd_t rnd1; + mp_rnd_t rnd2; + mp_prec_t prec; #endif { int k, k1, l, l1, tn; mp_limb_t cc, cc2, *tmp; @@ -266,12 +284,12 @@ mpfr_can_round_raw(bp, bn, neg, err, rnd1, rnd2, prec) switch (rnd1) { - case GMP_RNDZ: /* b <= x <= b+2^(EXP(b)-err) */ + case GMP_RNDZ: /* b <= x <= b+2^(MPFR_EXP(b)-err) */ tmp = TMP_ALLOC(tn*BYTES_PER_MP_LIMB); cc = (bp[bn-1]>>l1) & 1; cc ^= mpfr_round_raw2(bp, bn, neg, rnd2, prec); - /* now round b+2^(EXP(b)-err) */ + /* now round b+2^(MPFR_EXP(b)-err) */ cc2 = mpn_add_1(tmp+bn-k, bp+bn-k, k, (mp_limb_t)1<<l); /* if carry, then all bits up to err were to 1, and we can round only if cc==0 and mpfr_round_raw2 returns 0 below */ @@ -282,13 +300,13 @@ mpfr_can_round_raw(bp, bn, neg, err, rnd1, rnd2, prec) TMP_FREE(marker); return (cc == cc2); - case GMP_RNDU: /* b-2^(EXP(b)-err) <= x <= b */ + case GMP_RNDU: /* b-2^(MPFR_EXP(b)-err) <= x <= b */ tmp = TMP_ALLOC(tn*BYTES_PER_MP_LIMB); /* first round b */ cc = (bp[bn-1]>>l1) & 1; cc ^= mpfr_round_raw2(bp, bn, neg, rnd2, prec); - /* now round b-2^(EXP(b)-err) */ + /* now round b-2^(MPFR_EXP(b)-err) */ cc2 = mpn_sub_1(tmp+bn-k, bp+bn-k, k, (mp_limb_t)1<<l); /* if borrow, then all bits up to err were to 0, and we can round only if cc==0 and mpfr_round_raw2 returns 1 below */ @@ -299,12 +317,12 @@ mpfr_can_round_raw(bp, bn, neg, err, rnd1, rnd2, prec) TMP_FREE(marker); return (cc == cc2); - case GMP_RNDN: /* b-2^(EXP(b)-err-1) <= x <= b+2^(EXP(b)-err-1) */ + case GMP_RNDN: /* b-2^(MPFR_EXP(b)-err-1) <= x <= b+2^(MPFR_EXP(b)-err-1) */ if (l==0) tn++; tmp = TMP_ALLOC(tn*BYTES_PER_MP_LIMB); /* this case is the same than GMP_RNDZ, except we first have to - subtract 2^(EXP(b)-err-1) from b */ + subtract 2^(MPFR_EXP(b)-err-1) from b */ if (l) { l--; /* tn=bn */ @@ -316,14 +334,14 @@ mpfr_can_round_raw(bp, bn, neg, err, rnd1, rnd2, prec) mpn_sub_1(tmp+tn-k, tmp+tn-k, k, (mp_limb_t)1<<l); } - /* round b-2^(EXP(b)-err-1) */ + /* round b-2^(MPFR_EXP(b)-err-1) */ /* we can disregard borrow, since we start from tmp in 2nd case too */ cc = (tmp[tn-1]>>l1) & 1; cc ^= mpfr_round_raw2(tmp, tn, neg, rnd2, prec); if (l==BITS_PER_MP_LIMB-1) { l=0; k--; } else l++; - /* round b+2^(EXP(b)-err-1) = b-2^(EXP(b)-err-1) + 2^(EXP(b)-err) */ + /* round b+2^(MPFR_EXP(b)-err-1) = b-2^(MPFR_EXP(b)-err-1) + 2^(MPFR_EXP(b)-err) */ cc2 = mpn_add_1(tmp+tn-k, tmp+tn-k, k, (mp_limb_t)1<<l); /* if carry, then all bits up to err were to 1, and we can round only if cc==0 and mpfr_round_raw2 returns 0 below */ diff --git a/mpfr/set.c b/mpfr/set.c index 7177925fa..9544d6d51 100644 --- a/mpfr/set.c +++ b/mpfr/set.c @@ -1,6 +1,6 @@ /* mpfr_set -- copy of a floating-point number -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -23,22 +23,34 @@ MA 02111-1307, USA. */ #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" void #if __STDC__ -mpfr_set4(mpfr_ptr a, mpfr_srcptr b, unsigned char rnd_mode, int signb) +mpfr_set4 (mpfr_ptr a, mpfr_srcptr b, mp_rnd_t rnd_mode, int signb) #else -mpfr_set4(a, b, rnd_mode, signb) +mpfr_set4 (a, b, rnd_mode, signb) mpfr_ptr a; mpfr_srcptr b; - unsigned char rnd_mode; + mp_rnd_t rnd_mode; int signb; #endif { - int carry, an, preca = PREC(a), sh; mp_limb_t *ap = MANT(a); + int carry, an, preca = MPFR_PREC(a), sh; mp_limb_t *ap = MPFR_MANT(a); - carry = mpfr_round_raw(ap, MANT(b), PREC(b), (signb<0), preca, rnd_mode); - EXP(a) = EXP(b); + if (MPFR_IS_NAN(b)) + { MPFR_CLEAR_FLAGS(a); MPFR_SET_NAN(a); return; } + if (MPFR_IS_INF(b)) + { + MPFR_CLEAR_FLAGS(a); + MPFR_SET_INF(a); + if (MPFR_SIGN(a) * signb < 0) MPFR_CHANGE_SIGN(a); + return; + } + MPFR_CLEAR_FLAGS(a); + + carry = mpfr_round_raw(ap, MPFR_MANT(b), MPFR_PREC(b), (signb<0), preca, rnd_mode); + MPFR_EXP(a) = MPFR_EXP(b); if (carry) { an = (preca-1)/BITS_PER_MP_LIMB + 1; sh = an * BITS_PER_MP_LIMB - preca; @@ -47,7 +59,7 @@ mpfr_set4(a, b, rnd_mode, signb) } mpn_rshift(ap, ap, an, 1); ap[an-1] |= (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); - EXP(a)++; + MPFR_EXP(a)++; } - if (SIGN(a) != signb) CHANGE_SIGN(a); + if (MPFR_SIGN(a) * signb < 0) MPFR_CHANGE_SIGN(a); } diff --git a/mpfr/set_d.c b/mpfr/set_d.c index 35c3ba21f..fe8006aae 100644 --- a/mpfr/set_d.c +++ b/mpfr/set_d.c @@ -1,7 +1,7 @@ /* mpfr_set_d, mpfr_get_d -- convert a multiple precision floating-point number from/to a machine double precision float -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -20,17 +20,24 @@ along with the MPFR Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#if __GNUC__ /* gcc "patched" headers seem to omit isnan... */ -extern int isnan(double); -#endif -#include <math.h> /* for isnan and NaN */ - #include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" #include "gmp-impl.h" #include "longlong.h" -#include "mpfr.h" -#define NaN sqrt(-1) /* ensures a machine-independent NaN */ +#if (BITS_PER_MP_LIMB==32) +#define MPFR_LIMBS_PER_DOUBLE 2 +#elif (BITS_PER_MP_LIMB==64) +#define MPFR_LIMBS_PER_DOUBLE 1 +#endif + +int __mpfr_extract_double (mp_ptr, double, int); +double __mpfr_scale2 (double, int); + +#define NaN (0./0.) /* ensures a machine-independent NaN */ +#define Infp (1/0.) +#define Infm (-1/0.) /* Included from gmp-2.0.2, patched to support denorms */ @@ -235,39 +242,56 @@ __mpfr_scale2 (d, exp) void #if __STDC__ -mpfr_set_d(mpfr_t r, double d, unsigned char rnd_mode) +mpfr_set_d (mpfr_ptr r, double d, mp_rnd_t rnd_mode) #else -mpfr_set_d(r, d, rnd_mode) - mpfr_t r; +mpfr_set_d (r, d, rnd_mode) + mpfr_ptr r; double d; - unsigned char rnd_mode; + mp_rnd_t rnd_mode; #endif { int signd, sizer; unsigned int cnt; - if (d == 0) { SET_ZERO(r); return; } - else if (isnan(d)) { SET_NAN(r); return; } + MPFR_CLEAR_FLAGS(r); + if (d == 0) { + union ieee_double_extract x; + MPFR_SET_ZERO(r); + /* set correct sign */ + x.d = d; + if (((x.s.sig==1) && (MPFR_SIGN(r)>0)) + || ((x.s.sig==0) && (MPFR_SIGN(r)<0))) + MPFR_CHANGE_SIGN(r); + return; + } + else if (DOUBLE_ISNAN(d)) { MPFR_SET_NAN(r); return; } + else if (DOUBLE_ISINF(d)) + { + MPFR_SET_INF(r); + if ((d > 0 && (MPFR_SIGN(r) == -1)) || (d < 0 && (MPFR_SIGN(r) == 1))) + MPFR_CHANGE_SIGN(r); + return; + } signd = (d < 0) ? -1 : 1; d = ABS (d); - sizer = (PREC(r)-1)/BITS_PER_MP_LIMB + 1; + sizer = (MPFR_PREC(r)-1)/BITS_PER_MP_LIMB + 1; /* warning: __mpfr_extract_double requires at least two limbs */ if (sizer < MPFR_LIMBS_PER_DOUBLE) - EXP(r) = __mpfr_extract_double (MANT(r), d, 0); + MPFR_EXP(r) = __mpfr_extract_double (MPFR_MANT(r), d, 0); else - EXP(r) = __mpfr_extract_double (MANT(r) + sizer - MPFR_LIMBS_PER_DOUBLE, d, 1); + MPFR_EXP(r) = __mpfr_extract_double (MPFR_MANT(r) + sizer - MPFR_LIMBS_PER_DOUBLE, d, 1); if (sizer > MPFR_LIMBS_PER_DOUBLE) - MPN_ZERO(MANT(r), sizer - MPFR_LIMBS_PER_DOUBLE); + MPN_ZERO(MPFR_MANT(r), sizer - MPFR_LIMBS_PER_DOUBLE); - count_leading_zeros(cnt, MANT(r)[sizer-1]); - if (cnt) mpn_lshift(MANT(r), MANT(r), sizer, cnt); + count_leading_zeros(cnt, MPFR_MANT(r)[sizer-1]); + if (cnt) mpn_lshift(MPFR_MANT(r), MPFR_MANT(r), sizer, cnt); - EXP(r) -= cnt; - if (SIZE(r)*signd<0) CHANGE_SIGN(r); + MPFR_EXP(r) -= cnt; + if (MPFR_SIGN(r)*signd<0) MPFR_CHANGE_SIGN(r); - mpfr_round(r, rnd_mode, PREC(r)); + mpfr_round(r, rnd_mode, MPFR_PREC(r)); return; } @@ -285,15 +309,21 @@ mpfr_get_d2(src, e) mp_ptr qp; int negative; - if (FLAG_NAN(src)) { + if (MPFR_IS_NAN(src)) { #ifdef DEBUG printf("recognized NaN\n"); #endif return NaN; } - if (NOTZERO(src)==0) return 0.0; - size = 1+(PREC(src)-1)/BITS_PER_MP_LIMB; - qp = MANT(src); - negative = (SIGN(src)==-1); + if (MPFR_IS_INF(src)) { +#ifdef DEBUG + printf("Found Inf.\n"); +#endif + return (MPFR_SIGN(src) == 1 ? Infp : Infm); + } + if (MPFR_NOTZERO(src)==0) return 0.0; + size = 1+(MPFR_PREC(src)-1)/BITS_PER_MP_LIMB; + qp = MPFR_MANT(src); + negative = (MPFR_SIGN(src) < 0); /* Warning: don't compute the abs(res) and set the sign afterwards, otherwise the current machine rounding mode will not be taken @@ -324,6 +354,6 @@ mpfr_get_d(src) mpfr_srcptr src; #endif { - return mpfr_get_d2(src, EXP(src)); + return mpfr_get_d2(src, MPFR_EXP(src)); } diff --git a/mpfr/set_dfl_prec.c b/mpfr/set_dfl_prec.c index aa341be8a..f1ff78a08 100644 --- a/mpfr/set_dfl_prec.c +++ b/mpfr/set_dfl_prec.c @@ -1,6 +1,6 @@ /* mpfr_set_default_prec -- set the default precision -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -20,17 +20,18 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gmp.h" +#include "mpfr.h" #include "gmp-impl.h" /* default is 53 bits */ -mp_size_t __gmp_default_fp_bit_precision = 53; +mp_prec_t __gmp_default_fp_bit_precision = 53; void #if __STDC__ -mpfr_set_default_prec (unsigned long int prec_in_bits) +mpfr_set_default_prec (mp_prec_t prec_in_bits) #else mpfr_set_default_prec (prec_in_bits) - unsigned long int prec_in_bits; + mp_prec_t prec_in_bits; #endif { __gmp_default_fp_bit_precision = prec_in_bits; diff --git a/mpfr/set_f.c b/mpfr/set_f.c index d3bb98dbf..bcdacbfad 100644 --- a/mpfr/set_f.c +++ b/mpfr/set_f.c @@ -1,6 +1,6 @@ /* mpfr_set_f -- set a MPFR number from a GNU MPF number -Copyright (C) 1999-2000 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999-2000 Free Software Foundation. This file is part of the MPFR Library. @@ -24,31 +24,35 @@ MA 02111-1307, USA. */ #include "gmp-impl.h" #include "longlong.h" #include "mpfr.h" +#include "mpfr-impl.h" void #if __STDC__ -mpfr_set_f(mpfr_ptr y, mpf_srcptr x, char rnd_mode) +mpfr_set_f(mpfr_ptr y, mpf_srcptr x, mp_rnd_t rnd_mode) #else mpfr_set_f(y, x, rnd_mode) mpfr_ptr y; mpf_srcptr x; - char rnd_mode; + mp_rnd_t rnd_mode; #endif { mp_limb_t *my, *mx, *tmp; unsigned long cnt, sx, sy; TMP_DECL(marker); - sx = ABS(SIZ(x)); sy = ABSSIZE(y); - my = MANT(y); mx = MANT(x); + if (SIZ(x) * MPFR_SIGN(y) < 0) MPFR_CHANGE_SIGN(y); + + MPFR_CLEAR_FLAGS(y); + + TMP_MARK(marker); + sx = ABS(SIZ(x)); sy = MPFR_ABSSIZE(y); + my = MPFR_MANT(y); mx = PTR(x); if (sx==0) { /* x is zero */ - SET_ZERO(y); return; + MPFR_SET_ZERO(y); return; } count_leading_zeros(cnt, mx[sx - 1]); - if (SIZ(x)*SIGN(y)<0) CHANGE_SIGN(y); - if (sy < sx) { unsigned long xprec = sx * BITS_PER_MP_LIMB; @@ -56,7 +60,7 @@ mpfr_set_f(y, x, rnd_mode) tmp = (mp_limb_t*) TMP_ALLOC(xprec); if (cnt) mpn_lshift(tmp, mx, sx, cnt); else MPN_COPY(tmp, mx, sx); - mpfr_round_raw(my, tmp, xprec, (SIZ(x)<0), PREC(y), rnd_mode); + mpfr_round_raw(my, tmp, xprec, (SIZ(x)<0), MPFR_PREC(y), rnd_mode); } else { @@ -66,7 +70,7 @@ mpfr_set_f(y, x, rnd_mode) /* no rounding necessary, since y has a larger mantissa */ } - EXP(y) = EXP(x) * BITS_PER_MP_LIMB - cnt; + MPFR_EXP(y) = EXP(x) * BITS_PER_MP_LIMB - cnt; TMP_FREE(marker); } diff --git a/mpfr/set_prc_raw.c b/mpfr/set_prc_raw.c new file mode 100644 index 000000000..b7a1633dd --- /dev/null +++ b/mpfr/set_prc_raw.c @@ -0,0 +1,49 @@ +/* mpfr_set_prec_raw -- reset the precision of a floating-point number + +Copyright (C) 2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +void +#if __STDC__ +mpfr_set_prec_raw (mpfr_ptr x, mp_prec_t p) +#else +mpfr_set_prec_raw (x, p) + mpfr_ptr x; + mp_prec_t p; +#endif +{ + if (p==0) { + fprintf(stderr, "*** cannot set precision to 0 bits\n"); exit(1); + } + + if (p > MPFR_ABSSIZE(x) * BITS_PER_MP_LIMB) { + fprintf(stderr, "*** precision too large for allocated space\n"); + exit(1); + } + + MPFR_PREC(x) = p; +} + + diff --git a/mpfr/set_prec.c b/mpfr/set_prec.c index 418efe8eb..17adb5bb2 100644 --- a/mpfr/set_prec.c +++ b/mpfr/set_prec.c @@ -1,6 +1,6 @@ /* mpfr_set_prec -- reset the precision of a floating-point number -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -23,17 +23,18 @@ MA 02111-1307, USA. */ #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" void #if __STDC__ -mpfr_set_prec (mpfr_t x, unsigned long int p) +mpfr_set_prec (mpfr_ptr x, mp_prec_t p) #else mpfr_set_prec (x, p) - mpfr_t x; - unsigned long int p; + mpfr_ptr x; + mp_prec_t p; #endif { - unsigned long xsize; + mp_prec_t xsize; if (p==0) { printf("*** cannot set precision to 0 bits\n"); exit(1); @@ -41,22 +42,26 @@ mpfr_set_prec (x, p) xsize = (p - 1)/BITS_PER_MP_LIMB + 1; /* new limb size */ - if (xsize > ABSSIZE(x)) { - x -> _mp_d = (mp_ptr) (*__gmp_reallocate_func) - (x -> _mp_d, ABSSIZE(x)*BYTES_PER_MP_LIMB, xsize * BYTES_PER_MP_LIMB); - SIZE(x) = xsize; /* new number of allocated limbs */ + if (xsize > MPFR_ABSSIZE(x)) { + MPFR_MANT(x) = (mp_ptr) (*_mp_reallocate_func) (MPFR_MANT(x), + MPFR_ABSSIZE(x)*BYTES_PER_MP_LIMB, xsize * BYTES_PER_MP_LIMB); + if (MPFR_MANT(x) == NULL) { + fprintf (stderr, "Error in mpfr_set_prec: no more memory available\n"); + exit (1); + } + MPFR_SIZE(x) = xsize; /* new number of allocated limbs */ } - x -> _mp_prec = p; + MPFR_PREC(x) = p; } -unsigned long int +mp_prec_t #if __STDC__ -mpfr_get_prec (mpfr_t x) +mpfr_get_prec (mpfr_srcptr x) #else mpfr_get_prec (x) - mpfr_t x; + mpfr_srcptr x; #endif { - return x -> _mp_prec; + return MPFR_PREC(x); } diff --git a/mpfr/set_q.c b/mpfr/set_q.c new file mode 100644 index 000000000..c6c364d6e --- /dev/null +++ b/mpfr/set_q.c @@ -0,0 +1,64 @@ +/* mpfr_set_q -- set a floating-point number from a multiple-precision rational + +Copyright (C) 2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" +#include "gmp-impl.h" +#include "longlong.h" + +/* set f to the rational q */ +void +#if __STDC__ +mpfr_set_q (mpfr_ptr f, mpq_srcptr q, mp_rnd_t rnd) +#else +mpfr_set_q (f, q, rnd) + mpfr_ptr f; + mpq_srcptr q; + mp_rnd_t rnd; +#endif +{ + int sign; + mpz_srcptr num, den; + unsigned int prec; + mpfr_t n,d; + + MPFR_CLEAR_FLAGS(f); + num = mpq_numref(q); + sign = mpz_cmp_ui(num, 0); + if (sign==0) { + MPFR_SET_ZERO(f); + return; + } + + den = mpq_denref(q); + prec = MPFR_PREC(f); + mpfr_init2(n, mpz_sizeinbase(num, 2)); + mpfr_set_z(n, num, GMP_RNDZ); /* result is exact */ + mpfr_init2(d, mpz_sizeinbase(den, 2)); + mpfr_set_z(d, den, GMP_RNDZ); /* result is exact */ + MPFR_PREC(f) = prec; + mpfr_div(f, n, d, rnd); + mpfr_clear(n); mpfr_clear(d); +} + + + diff --git a/mpfr/set_rnd.c b/mpfr/set_rnd.c new file mode 100644 index 000000000..34e728b8e --- /dev/null +++ b/mpfr/set_rnd.c @@ -0,0 +1,38 @@ +/* mpfr_set_default_rounding_mode -- set the default rounding mode + +Copyright (C) 1999 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include "gmp.h" +#include "mpfr.h" +#include "gmp-impl.h" + +mp_rnd_t __gmp_default_rounding_mode = 0; + +void +#if __STDC__ +mpfr_set_default_rounding_mode (mp_rnd_t rnd_mode) +#else +mpfr_set_default_rounding_mode (rnd_mode) + mp_rnd_t rnd_mode; +#endif +{ + __gmp_default_rounding_mode = rnd_mode; +} + diff --git a/mpfr/set_si.c b/mpfr/set_si.c index b2d916cd1..9594682fe 100644 --- a/mpfr/set_si.c +++ b/mpfr/set_si.c @@ -1,6 +1,6 @@ /* mpfr_set_si, mpfr_set_ui -- set a MPFR number from a machine integer -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -24,57 +24,86 @@ MA 02111-1307, USA. */ #include "gmp-impl.h" #include "longlong.h" #include "mpfr.h" +#include "mpfr-impl.h" void #if __STDC__ -mpfr_set_si(mpfr_ptr x, long i, unsigned char rnd_mode) +mpfr_set_si (mpfr_ptr x, long int i, mp_rnd_t rnd_mode) #else -mpfr_set_si(x, i, rnd_mode) +mpfr_set_si (x, i, rnd_mode) mpfr_ptr x; - long i; - unsigned char rnd_mode; + long int i; + mp_rnd_t rnd_mode; #endif { - unsigned long xn, cnt; mp_limb_t ai; + unsigned long xn, cnt; mp_limb_t ai, *xp; - if (i==0) { SET_ZERO(x); return; } - xn = (PREC(x)-1)/BITS_PER_MP_LIMB; + MPFR_CLEAR_FLAGS(x); + if (i==0) { MPFR_SET_ZERO(x); return; } + xn = (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB; ai = ABS(i); count_leading_zeros(cnt, ai); - x -> _mp_d[xn] = ai << cnt; + xp = MPFR_MANT(x); + xp[xn] = ai << cnt; /* don't forget to put zero in lower limbs */ - MPN_ZERO(MANT(x), xn); - x -> _mp_exp = BITS_PER_MP_LIMB - cnt; + MPN_ZERO(xp, xn); + + MPFR_EXP(x) = BITS_PER_MP_LIMB - cnt; + + /* round if MPFR_PREC(x) smaller than length of i */ + if (MPFR_PREC(x) < BITS_PER_MP_LIMB-cnt) { + cnt = mpfr_round_raw(xp+xn, xp+xn, BITS_PER_MP_LIMB-cnt, (ai<0), MPFR_PREC(x), + rnd_mode); + if (cnt) { /* special case 1.000...000 */ + MPFR_EXP(x)++; + xp[xn] = ((mp_limb_t) 1) << (BITS_PER_MP_LIMB-1); + } + } + /* warning: don't change the precision of x! */ - if (i*SIGN(x) < 0) CHANGE_SIGN(x); + if (i*MPFR_SIGN(x) < 0) MPFR_CHANGE_SIGN(x); return; } void #if __STDC__ -mpfr_set_ui(mpfr_ptr x, unsigned long i, unsigned char rnd_mode) +mpfr_set_ui (mpfr_ptr x, unsigned long int i, mp_rnd_t rnd_mode) #else -mpfr_set_ui(x, i, rnd_mode) +mpfr_set_ui (x, i, rnd_mode) mpfr_ptr x; - long i; - unsigned char rnd_mode; + unsigned long int i; + mp_rnd_t rnd_mode; #endif { - unsigned int xn, cnt; + unsigned int xn, cnt; mp_limb_t *xp; - if (i==0) { SET_ZERO(x); return; } - xn = (PREC(x)-1)/BITS_PER_MP_LIMB; + MPFR_CLEAR_FLAGS(x); + if (i==0) { MPFR_SET_ZERO(x); return; } + xn = (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB; count_leading_zeros(cnt, (mp_limb_t) i); - x -> _mp_d[xn] = ((mp_limb_t) i) << cnt; + xp = MPFR_MANT(x); + xp[xn] = ((mp_limb_t) i) << cnt; /* don't forget to put zero in lower limbs */ - MPN_ZERO(MANT(x), xn); - x -> _mp_exp = BITS_PER_MP_LIMB - cnt; + MPN_ZERO(xp, xn); + + MPFR_EXP(x) = BITS_PER_MP_LIMB - cnt; + + /* round if MPFR_PREC(x) smaller than length of i */ + if (MPFR_PREC(x) < BITS_PER_MP_LIMB-cnt) { + cnt = mpfr_round_raw(xp+xn, xp+xn, BITS_PER_MP_LIMB-cnt, 0, MPFR_PREC(x), + rnd_mode); + if (cnt) { /* special case 1.000...000 */ + MPFR_EXP(x)++; + xp[xn] = ((mp_limb_t) 1) << (BITS_PER_MP_LIMB-1); + } + } + /* warning: don't change the precision of x! */ - if (SIGN(x) < 0) CHANGE_SIGN(x); + if (MPFR_SIGN(x) < 0) MPFR_CHANGE_SIGN(x); return; } diff --git a/mpfr/set_str.c b/mpfr/set_str.c new file mode 100644 index 000000000..0c0b029cf --- /dev/null +++ b/mpfr/set_str.c @@ -0,0 +1,155 @@ +/* mpfr_set_str -- set a floating-point number from a string + +Copyright (C) 2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#ifdef HAS_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +int +#if __STDC__ +mpfr_set_str(mpfr_ptr x, char *str, int base, mp_rnd_t rnd_mode) +#else +mpfr_set_str(x, str, base, rnd_mode) + mpfr_ptr x; + char *str; + int base; + mp_rnd_t rnd_mode; +#endif +{ + char negative = 0, *endptr; + unsigned long k = 0, l, q; + long expn = 0, e; + mpz_t mantissa; + mpfr_t y, z; + + mpz_init(mantissa); mpz_set_ui(mantissa, 0); + l = strlen(str); + if (*str == '-') { negative = 1; str++; l--; } + else if (*str == '+') { str++; l--; } + + while (*str == '0') { str++; l--; } /* skip initial zeros */ + + /* allowed characters are '0' to '0'+base-1 if base <= 10, + and '0' to '9' plus 'a' to 'a'+base-11 if 10 < base <= 36 */ + while ((isdigit((unsigned char) *str) && (unsigned char) *str < '0'+base) + || (islower((unsigned char) *str) && (unsigned char) *str < 'a'+base-10)) + { + mpz_mul_ui(mantissa, mantissa, base); + mpz_add_ui(mantissa, mantissa, isdigit((unsigned char) *str) ? + (*str)-'0' : (*str)-'a'+10); + str++; l--; + } + + /* k is the number of non-zero digits before the decimal point */ + + if (*str == '.') + { + str++; l--; + while ((isdigit((unsigned char) *str) && (unsigned char) *str < '0'+base) + || (islower((unsigned char) *str) && (unsigned char) *str < 'a'+base-10)) + { + mpz_mul_ui(mantissa, mantissa, base); + mpz_add_ui(mantissa, mantissa, isdigit((unsigned char) *str) ? + (*str)-'0' : (*str)-'a'+10); + str++; l--; + k++; + } + } + + if ((base <= 10 && (*str == 'e' || *str == 'E')) || *str == '@') + { + str++; l--; + e = strtol(str, &endptr, 10); /* signed exponent after 'e', 'E' or '@' */ + expn = e - k; + if (expn > e) + fprintf(stderr, "Warning: exponent underflow in mpfr_set_str\n"); + } + else if (l) { + fprintf(stderr, "Unexpected end of string in mpfr_set_str: %s\n", str); + return -1; + } + else { + expn = -k; + endptr = str; + } + + /* the number is mantissa*base^expn */ + + q = (MPFR_PREC(x)/BITS_PER_MP_LIMB)*BITS_PER_MP_LIMB; + mpfr_init(y); + mpfr_init(z); + + do { + q += BITS_PER_MP_LIMB; + mpfr_set_prec(y, q); + mpfr_set_z(y, mantissa, GMP_RNDN); /* error <= 1/2*ulp(y) */ + + mpfr_set_prec(z, q); + if (expn>0) { + e = mpfr_ui_pow_ui(z, base, expn, GMP_RNDN); + mpfr_mul(y, y, z, GMP_RNDN); + } + else if (expn<0) { + e = mpfr_ui_pow_ui(z, base, -expn, GMP_RNDN); + mpfr_div(y, y, z, GMP_RNDN); + } + else e=1; + if (negative) mpfr_neg(y, y, GMP_RNDN); + + /* now y is an approximation of mantissa*base^expn with error at most + 2^e*ulp(y) */ + + } while (mpfr_can_round(y, q-e, GMP_RNDN, rnd_mode, MPFR_PREC(x))==0 + && q<=2*MPFR_PREC(x)); + + mpfr_set(x, y, rnd_mode); + + mpz_clear(mantissa); + mpfr_clear(y); + mpfr_clear(z); + return ((*endptr=='\0') ? 0 : -1); +} + +int +#if __STDC__ +mpfr_init_set_str(mpfr_ptr x, char *str, int base, mp_rnd_t rnd_mode) +#else +mpfr_init_set_str(x, str, base, rnd_mode) + mpfr_ptr x; + char *str; + int base; + mp_rnd_t rnd_mode; +#endif +{ + mpfr_init(x); + return mpfr_set_str(x, str, base, rnd_mode); +} + diff --git a/mpfr/set_str_raw.c b/mpfr/set_str_raw.c index d0945c4bc..e00645cef 100644 --- a/mpfr/set_str_raw.c +++ b/mpfr/set_str_raw.c @@ -1,6 +1,6 @@ /* mpfr_set_str_raw -- set a floating-point number from a binary string -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -30,6 +30,7 @@ MA 02111-1307, USA. */ #include "gmp-impl.h" #include "longlong.h" #include "mpfr.h" +#include "mpfr-impl.h" /* Currently the number should be of the form +/- xxxx.xxxxxxEyy, with decimal exponent. The mantissa of x is supposed to be large enough @@ -37,24 +38,45 @@ MA 02111-1307, USA. */ void #if __STDC__ -mpfr_set_str_raw(mpfr_ptr x, char *str) +mpfr_set_str_raw (mpfr_ptr x, char *str) #else -mpfr_set_str_raw(x, str) +mpfr_set_str_raw (x, str) mpfr_ptr x; char *str; #endif { char *str2, *str0, negative = 0; - unsigned long j, l, k = 0, xsize, cnt; mp_limb_t *xp; + unsigned long j, l, k = 0, xsize, cnt, alloc; mp_limb_t *xp; long expn = 0, e; char *endstr2; - xp = x -> _mp_d; - xsize = 1 + (PREC(x)-1)/BITS_PER_MP_LIMB; - str0 = str2 = (char *) malloc((strlen(str)+1)*sizeof(char)); + xp = MPFR_MANT(x); + xsize = 1 + (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB; + alloc = (strlen(str)+1) * sizeof(char); + str0 = str2 = (char *) (*_mp_allocate_func) (alloc); + + if (str0 == NULL) { + fprintf (stderr, "Error in mpfr_set_str_raw: no more memory available\n"); + exit (1); + } if (*str == '-') { negative = 1; str++; } else if (*str == '+') str++; + + if (*str == 'I') + { + MPFR_SET_INF(x); + if (MPFR_ISNEG(x) != negative) MPFR_CHANGE_SIGN(x); + return; + } + + if (*str == 'N') + { + MPFR_SET_NAN(x); + return; + } + MPFR_CLEAR_FLAGS(x); + while (*str == '0') { str++; } while (*str == '0' || *str == '1') @@ -82,7 +104,11 @@ mpfr_set_str_raw(x, str) endstr2 = str2; *str2 = (char) 0; /* end of string */ - l = (strlen(str0) - 1) / BITS_PER_MP_LIMB + 1; str2 = str0; + l = (strlen(str0) - 1) / BITS_PER_MP_LIMB + 1; str2 = str0; + if (l > xsize) { + fprintf (stderr, "Error: mantissa larger than precision of destination variable in mpfr_set_str_raw\n"); + exit (1); + } /* str2[0]..endstr2[-1] contains the mantissa */ for (k = 1; k <= l; k++) @@ -102,10 +128,10 @@ mpfr_set_str_raw(x, str) count_leading_zeros(cnt, xp[xsize - 1]); if (cnt) mpn_lshift(xp, xp, xsize, cnt); - x -> _mp_exp = expn - cnt; - x -> _mp_size = xsize; if (negative) CHANGE_SIGN(x); + MPFR_EXP(x) = expn - cnt; + MPFR_SIZE(x) = xsize; if (negative) MPFR_CHANGE_SIGN(x); - free(str0); + (*_mp_free_func) (str0, alloc); /* May change to take into account : syntax errors, overflow in exponent, string truncated because of size of x */ diff --git a/mpfr/set_z.c b/mpfr/set_z.c index de9132033..0815ca324 100644 --- a/mpfr/set_z.c +++ b/mpfr/set_z.c @@ -1,6 +1,6 @@ /* mpfr_set_z -- set a floating-point number from a multiple-precision integer -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -20,39 +20,47 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" #include "gmp-impl.h" #include "longlong.h" -#include "mpfr.h" /* set f to the integer z */ int #if __STDC__ -mpfr_set_z (mpfr_ptr f, mpz_srcptr z, unsigned char rnd) +mpfr_set_z (mpfr_ptr f, mpz_srcptr z, mp_rnd_t rnd) #else mpfr_set_z (f, z, rnd) - mpfr_ptr f; - mpz_srcptr z; - unsigned char rnd; + mpfr_ptr f; + mpz_srcptr z; + mp_rnd_t rnd; #endif { - int fn, zn, k, dif, sign_z, sh; mp_limb_t *fp = MANT(f), *zp, cc, c2; + int fn, zn, k, dif, sign_z, sh; mp_limb_t *fp = MPFR_MANT(f), *zp, cc, c2; + + MPFR_CLEAR_FLAGS (f); /* z cannot be NaN nor Inf */ + + sign_z = mpz_cmp_ui (z, 0); + + if (sign_z==0) { + MPFR_SET_ZERO(f); + return 0; + } - sign_z = mpz_cmp_ui(z,0); - if (sign_z==0) return (SIZE(f)=0); - fn = 1 + (PREC(f)-1)/BITS_PER_MP_LIMB; + fn = 1 + (MPFR_PREC(f)-1)/BITS_PER_MP_LIMB; zn = ABS(SIZ(z)); dif = zn-fn; zp = PTR(z); count_leading_zeros(k, zp[zn-1]); - EXP(f) = zn*BITS_PER_MP_LIMB-k; - if (SIGN(f)*sign_z<0) CHANGE_SIGN(f); + MPFR_EXP(f) = zn*BITS_PER_MP_LIMB-k; + if (MPFR_SIGN(f)*sign_z<0) MPFR_CHANGE_SIGN(f); if (dif>=0) { /* number has to be truncated */ if (k) { mpn_lshift(fp, zp + dif, fn, k); if (dif) *fp += zp[dif-1] >> (BITS_PER_MP_LIMB-k); } else MPN_COPY(fp, zp + dif, fn); - sh = fn*BITS_PER_MP_LIMB-PREC(f); + sh = fn*BITS_PER_MP_LIMB-MPFR_PREC(f); cc = *fp & (((mp_limb_t)1 << sh) - 1); *fp = *fp & ~cc; if (rnd==GMP_RNDN) { diff --git a/mpfr/sin_cos.c b/mpfr/sin_cos.c new file mode 100644 index 000000000..21f746b70 --- /dev/null +++ b/mpfr/sin_cos.c @@ -0,0 +1,246 @@ +/* mpfr_sin_cos -- sine and cosine of a floating-point number + +Copyright (C) 2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +int mpfr_sin_aux (mpfr_ptr, mpz_srcptr, int, int); +int mpfr_cos_aux (mpfr_ptr, mpz_srcptr, int, int); + +#undef A +#undef B +#define C +#define C1 3 +#define C2 2 +#define GENERIC mpfr_sin_aux +#include "generic.c" +#undef C +#undef C1 +#undef C2 +#undef GENERIC + +#undef A +#undef B +#define C +#define C1 1 +#define C2 2 +#define GENERIC mpfr_cos_aux +#include "generic.c" + +#define shift (BITS_PER_MP_LIMB / 2) + +int +#if __STDC__ +mpfr_sin_cos (mpfr_ptr sinus, mpfr_ptr cosinus, mpfr_srcptr x, mp_rnd_t rnd_mode) +#else +mpfr_sin_cos (sinus, cosinus, x, rnd_mode) + mpfr_ptr sinus; + mpfr_ptr cosinus; + mpfr_srcptr x; + mp_rnd_t rnd_mode; +#endif +{ + mpfr_t t_sin, t_cos; + mpfr_t x_copy; + int i,k; + mpz_t uk; + mpz_t square; + mpfr_t tmp_sin, tmp_cos; + mpfr_t tmp; + mpfr_t inter; + int ttt; + int twopoweri; + int Prec; + int loop; + int prec_x; + int shift_x = 0; + int good = 0; + int realprec = 0, target_prec; + int iter; + int factor; + int logn; + int tmp_factor; + int tmpi; + + if (sinus == cosinus) { + fprintf (stderr, "Error in mpfr_sin_cos: 1st and 2nd operands must be different\n"); + exit (1); + } + + if (MPFR_IS_NAN(x) || MPFR_IS_INF(x)) { + MPFR_SET_NAN(sinus); + MPFR_SET_NAN(cosinus); + return 1; /* inexact */ + } + + if (!MPFR_NOTZERO(x)) { + mpfr_set_ui(sinus, 0, GMP_RNDN); + mpfr_set_ui(cosinus, 1, GMP_RNDN); + return 0; /* exact results */ + } + + prec_x = _mpfr_ceil_log2 ((double) MPFR_PREC(x) / BITS_PER_MP_LIMB); + ttt = MPFR_EXP(x); + mpfr_init2(x_copy, MPFR_PREC(x)); + mpfr_set(x_copy,x,GMP_RNDD); + mpz_init(square); + /* on fait le shift pour que le nombre soit inferieur a 1 */ + if (ttt > 0) + { + shift_x = ttt; + mpfr_mul_2exp(x_copy,x,-ttt, GMP_RNDN); + ttt = MPFR_EXP(x_copy); + } + target_prec = MPFR_PREC(sinus); + if (MPFR_PREC(cosinus) > target_prec) target_prec = MPFR_PREC(cosinus); + logn = _mpfr_ceil_log2 ((double) target_prec); + if (logn < 2) logn = 2; + factor = logn; + realprec = target_prec + logn; + mpz_init (uk); + while (!good) { + Prec = realprec + 2*shift + 2 + shift_x + factor; + k = _mpfr_ceil_log2 ((double) Prec / BITS_PER_MP_LIMB); + + /* now we extract */ + mpfr_init2(t_sin, Prec); + mpfr_init2(t_cos, Prec); + mpfr_init2(tmp, Prec); + mpfr_init2(tmp_sin, Prec); + mpfr_init2(tmp_cos, Prec); + mpfr_init2(inter, Prec); + mpfr_set_ui(tmp_sin,0,GMP_RNDN); + mpfr_set_ui(tmp_cos,1,GMP_RNDN); + twopoweri = BITS_PER_MP_LIMB; + if (k <= prec_x) iter = k; else iter= prec_x; + for(i = 0; i <= iter; i++){ + mpfr_extract (uk, x_copy, i); + if (i) + { + mpz_mul (square, uk, uk); + mpz_neg (square, square); + mpfr_sin_aux (t_sin, square, 2*(twopoweri - ttt) + 2, k - i + 1); + mpfr_cos_aux (t_cos, square, 2*(twopoweri - ttt) + 2, k - i + 1); + mpfr_set_z (tmp, uk, GMP_RNDD); + mpfr_mul (t_sin, t_sin, tmp, GMP_RNDD); + mpfr_div_2exp (t_sin, t_sin, twopoweri - ttt, GMP_RNDD); + } + else + { + /* cas particulier : on est oblige de faire les calculs avec x/2^. + puis elever au carre (plus rapide) */ + mpz_set (square, uk); + mpz_mul(square, square, square); + mpz_neg(square, square); + /* pour l'instant, shift = 0 ... */ + /* ATTENTION, IL FAUT AUSSI MULTIPLIER LE DENOMINATEUR */ + mpfr_sin_aux(t_sin,square, 2*(shift + twopoweri - ttt) + 2, k+1); + mpfr_cos_aux(t_cos,square, 2*(shift + twopoweri - ttt) + 2, k+1); + mpfr_set_z (tmp, uk, GMP_RNDD); + mpfr_mul(t_sin, t_sin, tmp,GMP_RNDD); + /* LA AUSSI, IL FAUT PENSER A DECALER DE twopoweri - ttt) */ + mpfr_div_2exp(t_sin,t_sin, twopoweri - ttt + shift, GMP_RNDD); + for (loop= 0 ; loop < shift; loop++){ + /* t_sin = sin(a) + t_cos = cos(a) */ + /* on veut t_sin = 2 sin a cos a + et t_cos = 2 * cos^2 - 1 */ + mpfr_mul(t_sin, t_sin, t_cos, GMP_RNDD); + mpfr_mul_2exp(t_sin, t_sin, 1, GMP_RNDD); + + mpfr_mul(t_cos, t_cos, t_cos, GMP_RNDD); + mpfr_mul_2exp(t_cos, t_cos, 1, GMP_RNDD); + mpfr_sub_ui(t_cos, t_cos, 1, GMP_RNDD); + } + } + /* on utilise cos(a+b) = cos a cos b - sin a sin b + sin(a+b) = sin a cos b + cos a sin b */ + /* Donnees : + tmp = cos(a) + tmp_sin = sin(a) + t_sin = sin(b) + t_cos = cos(b) */ + mpfr_set(tmp, tmp_cos,GMP_RNDD); + /* inter = sin a sin b */ + mpfr_mul(inter, tmp_sin, t_sin, GMP_RNDD); + /* tmp_cos = cos a cos b */ + mpfr_mul(tmp_cos, tmp_cos, t_cos, GMP_RNDD); + /* tmp_cos = cos (a+b) */ + mpfr_sub(tmp_cos, tmp_cos, inter, GMP_RNDD); + /* inter = cos a sin b */ + mpfr_mul(inter, tmp, t_sin, GMP_RNDD); + /* tmp_sin = sin a cos b */ + mpfr_mul(tmp_sin, tmp_sin, t_cos, GMP_RNDD); + /* tmp_sin = sin (a+b) */ + mpfr_add(tmp_sin, tmp_sin, inter, GMP_RNDD); + twopoweri <<= 1; + } + tmp_factor= factor; + for (loop= 0 ; loop < shift_x; loop++){ + mpfr_mul(tmp_sin, tmp_sin, tmp_cos, GMP_RNDD); + mpfr_mul_2exp(tmp_sin, tmp_sin, 1, GMP_RNDD); + mpfr_mul(tmp_cos, tmp_cos, tmp_cos, GMP_RNDD); + mpfr_mul_2exp(tmp_cos, tmp_cos, 1, GMP_RNDD); + tmpi = -MPFR_EXP(tmp_cos); + mpfr_set_ui(tmp, 1, GMP_RNDN); + mpfr_sub(tmp_cos, tmp_cos, tmp, GMP_RNDD); + /* rep\'erer si le nombre de chiffres obtenu est suffisant pour + avoir la bonne pr\'ecision. Le probl\`eme : comment faire ? + la pr\'ecision s'obtient en comparant + (Prec-factor) a la pr\'ecision obtenue r\'eellement, celle-ci + \'etant donn\'ee par Prec + MPFR_EXP(tmp_cos). + il faut donc comparer MPFR_EXP(tmp_cos) a factor */ + tmp_factor -= -MPFR_EXP(tmp_cos) + tmpi; + if (tmp_factor <= 0) + { + factor += -tmp_factor + 5; + goto try_again; + } + } + if (mpfr_can_round(tmp_sin, realprec, GMP_RNDD, rnd_mode, MPFR_PREC(sinus)) && + mpfr_can_round(tmp_cos, realprec, GMP_RNDD, rnd_mode, MPFR_PREC(cosinus))) { + mpfr_set(sinus, tmp_sin, rnd_mode); + mpfr_set(cosinus, tmp_cos, rnd_mode); + good = 1; + } + else { + realprec += 3*logn; + } + try_again: + mpfr_clear(t_sin); + mpfr_clear(t_cos); + mpfr_clear(tmp); + mpfr_clear(tmp_sin); + mpfr_clear(tmp_cos); + mpfr_clear(inter); + } + mpz_clear (uk); + mpz_clear (square); + mpfr_clear (x_copy); + return 1; /* inexact result */ +} + + + diff --git a/mpfr/sqrt.c b/mpfr/sqrt.c index a34ff6dae..19d0f14b1 100644 --- a/mpfr/sqrt.c +++ b/mpfr/sqrt.c @@ -1,6 +1,6 @@ /* mpfr_sqrt -- square root of a floating-point number -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -19,18 +19,24 @@ along with the MPFR Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include <math.h> #include <stdio.h> #include <stdlib.h> #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" -#include "longlong.h" +#include "mpfr-impl.h" /* #define DEBUG */ int -mpfr_sqrt (mpfr_ptr r, mpfr_srcptr u, unsigned char rnd_mode) +#if __STDC__ +mpfr_sqrt (mpfr_ptr r, mpfr_srcptr u, mp_rnd_t rnd_mode) +#else +mpfr_sqrt (r, u, rnd_mode) + mpfr_ptr r; + mpfr_srcptr u; + mp_rnd_t rnd_mode; +#endif { mp_ptr up, rp, tmp, remp; mp_size_t usize, rrsize; @@ -38,23 +44,52 @@ mpfr_sqrt (mpfr_ptr r, mpfr_srcptr u, unsigned char rnd_mode) mp_size_t prec, err; mp_limb_t q_limb; long rw, nw, k; - int exact = 0; + int exact = 0, t; unsigned long cc = 0; char can_round = 0; TMP_DECL (marker); TMP_DECL(marker0); - if (FLAG_NAN(u) || SIGN(u) == -1) { SET_NAN(r); return 0; } - - prec = PREC(r); + if (MPFR_IS_NAN(u)) { + MPFR_SET_NAN(r); + return 1; + } + + if (MPFR_SIGN(u) < 0) { + if (MPFR_IS_INF(u) || MPFR_NOTZERO(u)) { + MPFR_SET_NAN(r); + return 1; + } + else { /* sqrt(-0) = -0 */ + MPFR_SET_ZERO(r); + if (MPFR_SIGN(r) > 0) MPFR_CHANGE_SIGN(r); + return 0; + } + } - if (!NOTZERO(u)) + MPFR_CLEAR_NAN(r); + + if (MPFR_SIGN(r) < 0) MPFR_CHANGE_SIGN(r); + if (MPFR_IS_INF(u)) + { + MPFR_SET_INF(r); + return 1; + } + + MPFR_CLEAR_INF(r); + + prec = MPFR_PREC(r); + + if (!MPFR_NOTZERO(u)) { - EXP(r) = 0; - MPN_ZERO(MANT(r), ABSSIZE(r)); - return 1; + MPFR_EXP(r) = 0; + rsize = (prec-1)/BITS_PER_MP_LIMB + 1; + MPN_ZERO(MPFR_MANT(r), rsize); + return 0; } - up = MANT(u); + up = MPFR_MANT(u); + + usize = (MPFR_PREC(u) - 1)/BITS_PER_MP_LIMB + 1; #ifdef DEBUG printf("Entering square root : "); @@ -64,9 +99,8 @@ mpfr_sqrt (mpfr_ptr r, mpfr_srcptr u, unsigned char rnd_mode) /* Compare the mantissas */ - usize = (PREC(u) - 1)/BITS_PER_MP_LIMB + 1; - rsize = ((PREC(r) + 2 + (EXP(u) & 1))/BITS_PER_MP_LIMB + 1) << 1; - rrsize = (PREC(r) + 2 + (EXP(u) & 1))/BITS_PER_MP_LIMB + 1; + rsize = ((MPFR_PREC(r) + 2 + (MPFR_EXP(u) & 1))/BITS_PER_MP_LIMB + 1) << 1; + rrsize = (MPFR_PREC(r) + 2 + (MPFR_EXP(u) & 1))/BITS_PER_MP_LIMB + 1; /* One extra bit is needed in order to get the square root with enough precision ; take one extra bit for rrsize in order to solve more easily the problem of rounding to nearest. @@ -76,24 +110,24 @@ mpfr_sqrt (mpfr_ptr r, mpfr_srcptr u, unsigned char rnd_mode) */ TMP_MARK(marker0); - if (EXP(u) & 1) /* Shift u one bit to the right */ + if (MPFR_EXP(u) & 1) /* Shift u one bit to the right */ { - if (PREC(u) & (BITS_PER_MP_LIMB - 1)) + if (MPFR_PREC(u) & (BITS_PER_MP_LIMB - 1)) { up = TMP_ALLOC(usize*BYTES_PER_MP_LIMB); - mpn_rshift(up, u->_mp_d, usize, 1); + mpn_rshift(up, MPFR_MANT(u), usize, 1); } else { up = TMP_ALLOC((usize + 1)*BYTES_PER_MP_LIMB); - if (mpn_rshift(up + 1, u->_mp_d, ABSSIZE(u), 1)) + if (mpn_rshift(up + 1, MPFR_MANT(u), usize, 1)) up [0] = ((mp_limb_t) 1) << (BITS_PER_MP_LIMB - 1); else up[0] = 0; usize++; } } - EXP(r) = ((EXP(u) + (EXP(u) & 1)) / 2) ; + MPFR_EXP(r) = ((MPFR_EXP(u) + (MPFR_EXP(u) & 1)) / 2) ; do { @@ -121,11 +155,11 @@ mpfr_sqrt (mpfr_ptr r, mpfr_srcptr u, unsigned char rnd_mode) #ifdef DEBUG printf("Taking the sqrt of : "); for(k = rsize - 1; k >= 0; k--) { - printf("+%lu*2^%lu",tmp[k],k*mp_bits_per_limb); } + printf("+%lu*2^%lu",tmp[k],k*BITS_PER_MP_LIMB); } printf(".\n"); #endif - q_limb = kara_sqrtrem (rp, remp, tmp, rsize); + q_limb = mpn_sqrtrem_new (rp, remp, tmp, rsize); #ifdef DEBUG printf("The result is : \n"); @@ -135,7 +169,7 @@ mpfr_sqrt (mpfr_ptr r, mpfr_srcptr u, unsigned char rnd_mode) #endif can_round = (mpfr_can_round_raw(rp, rrsize, 1, err, - GMP_RNDZ, rnd_mode, PREC(r))); + GMP_RNDZ, rnd_mode, MPFR_PREC(r))); /* If we used all the limbs of both the dividend and the divisor, then we have the correct RNDZ rounding */ @@ -167,8 +201,8 @@ mpfr_sqrt (mpfr_ptr r, mpfr_srcptr u, unsigned char rnd_mode) if (can_round) { - cc = mpfr_round_raw(rp, rp, err, 0, PREC(r), rnd_mode); - rrsize = (PREC(r) - 1)/BITS_PER_MP_LIMB + 1; + cc = mpfr_round_raw(rp, rp, err, 0, MPFR_PREC(r), rnd_mode); + rrsize = (MPFR_PREC(r) - 1)/BITS_PER_MP_LIMB + 1; } else /* Use the return value of sqrtrem to decide of the rounding */ @@ -184,7 +218,7 @@ mpfr_sqrt (mpfr_ptr r, mpfr_srcptr u, unsigned char rnd_mode) case GMP_RNDN : /* Not in the situation ...0 111111 */ - rw = (PREC(r) + 1) & (BITS_PER_MP_LIMB - 1); + rw = (MPFR_PREC(r) + 1) & (BITS_PER_MP_LIMB - 1); if (rw) { rw = BITS_PER_MP_LIMB - rw; nw = 0; } else nw = 1; if ((rp[nw] >> rw) & 1 && /* Not 0111111111 */ (q_limb || /* Nonzero remainder */ @@ -195,26 +229,33 @@ mpfr_sqrt (mpfr_ptr r, mpfr_srcptr u, unsigned char rnd_mode) case GMP_RNDU : if (q_limb) - cc = mpn_add_1(rp, rp, rrsize, 1 << (BITS_PER_MP_LIMB - - (PREC(r) & - (BITS_PER_MP_LIMB - 1)))); + { + t = MPFR_PREC(r) & (BITS_PER_MP_LIMB - 1); + if (t) + { + cc = mpn_add_1(rp, rp, rrsize, 1 << (BITS_PER_MP_LIMB - t)); + } + else + cc = mpn_add_1 (rp, rp, rrsize, 1); + } } if (cc) { mpn_rshift(rp, rp, rrsize, 1); rp[rrsize-1] |= (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); - r->_mp_exp++; + MPFR_EXP(r)++; } fin: rsize = rrsize; - rrsize = (PREC(r) - 1)/BITS_PER_MP_LIMB + 1; - MPN_COPY(r->_mp_d, rp + rsize - rrsize, rrsize); + rrsize = (MPFR_PREC(r) - 1)/BITS_PER_MP_LIMB + 1; + MPN_COPY(MPFR_MANT(r), rp + rsize - rrsize, rrsize); - if (PREC(r) & (BITS_PER_MP_LIMB - 1)) - MANT(r) [0] &= ~(((mp_limb_t)1 << (BITS_PER_MP_LIMB - - (PREC(r) & (BITS_PER_MP_LIMB - 1)))) - 1) ; + if (MPFR_PREC(r) & (BITS_PER_MP_LIMB - 1)) + MPFR_MANT(r) [0] &= ~(((mp_limb_t)1 << (BITS_PER_MP_LIMB - + (MPFR_PREC(r) & (BITS_PER_MP_LIMB - 1)))) - 1) ; - TMP_FREE(marker0); TMP_FREE (marker); - return exact; + TMP_FREE (marker); + TMP_FREE(marker0); + return exact; } diff --git a/mpfr/sqrt_ui.c b/mpfr/sqrt_ui.c new file mode 100644 index 000000000..3453e3d0f --- /dev/null +++ b/mpfr/sqrt_ui.c @@ -0,0 +1,58 @@ +/* mpfr_sqrt_ui -- square root of a machine integer + +Copyright (C) 2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +int +#if __STDC__ +mpfr_sqrt_ui (mpfr_ptr r, unsigned long u, mp_rnd_t rnd_mode) +#else +mpfr_sqrt_ui (r, u, rnd_mode) + mpfr_ptr r; + unsigned long u; + mp_rnd_t rnd_mode; +#endif +{ + int error = 0; + mpfr_t uu; + mp_limb_t up[1]; + unsigned long cnt; + + if (u) { /* if u=0, do nothing */ + MPFR_INIT1(up, uu, BITS_PER_MP_LIMB, 1); + count_leading_zeros(cnt, (mp_limb_t) u); + *up = (mp_limb_t) u << cnt; + MPFR_EXP(uu) = BITS_PER_MP_LIMB-cnt; + + error = mpfr_sqrt(r, uu, rnd_mode); + } + else { + MPFR_CLEAR_FLAGS(r); + MPFR_SET_ZERO(r); + } + return error; +} diff --git a/mpfr/sqrtrem.c b/mpfr/sqrtrem.c new file mode 100644 index 000000000..740d56997 --- /dev/null +++ b/mpfr/sqrtrem.c @@ -0,0 +1,225 @@ +/* mpn_sqrtrem_new -- integer square root with remainder + (should be directly integrated in a future release of GNU MP) + +Copyright (C) 2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> /* for NULL */ +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" + +mp_size_t mpn_sqrtrem1 (mp_ptr, mp_ptr, mp_srcptr); +mp_limb_t mpn_sqrtrem2 (mp_ptr, mp_ptr, mp_srcptr); +mp_limb_t mpn_dq_sqrtrem (mp_ptr, mp_ptr, mp_size_t); +mp_size_t mpn_sqrtrem_new (mp_ptr, mp_ptr, mp_srcptr, mp_size_t); + +/* table generated by isqrt(2^8*i) $ i=64..255 in MuPAD */ +static const unsigned char approx_tab[192] = { +128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, + 154, 155, 155, 156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, + 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175, + 176, 176, 177, 178, 178, 179, 180, 181, 181, 182, 183, 183, 184, 185, + 185, 186, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 193, 194, + 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201, 202, 203, 203, + 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211, 212, + 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, + 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, + 229, 229, 230, 230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, + 236, 237, 237, 238, 238, 239, 240, 240, 241, 241, 242, 242, 243, 243, + 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, + 251, 251, 252, 252, 253, 253, 254, 254, 255}; + +/* same as mpn_sqrtrem, but for size=1 and {np, 1} normalized */ +mp_size_t mpn_sqrtrem1 (mp_ptr sp, mp_ptr rp, mp_srcptr np) +{ + mp_limb_t np0, s, r, q, u; + int prec; + + /* first compute a 8-bit approximation from the high 8-bits of np[0] */ + np0 = np[0]; + q = np0 >> (BITS_PER_MP_LIMB - 8); + /* 2^6 = 64 <= q < 256 = 2^8 */ + s = approx_tab[q - 64]; /* 128 <= s < 255 */ + r = (np0 >> (BITS_PER_MP_LIMB - 16)) - s * s; /* r <= 2*s */ + if (r > 2 * s) { r -= 2 * s + 1; s++; } +#ifdef DEBUG + if (r > 2*s) { + fprintf(stderr, "Error: r > 2*s, np[0]=%lu r=%lu s=%lu\n", np[0], r, s); exit(1); + } +#endif + + prec = 8; + np0 <<= 2 * prec; + while (2*prec < BITS_PER_MP_LIMB) { + /* invariant: s has prec bits, and r <= 2*s */ + r = (r << prec) + (np0 >> (BITS_PER_MP_LIMB - prec)); + np0 <<= prec; + u = 2 * s; + q = r / u; + u = r - q * u; + s = (s << prec) + q; + u = (u << prec) + (np0 >> (BITS_PER_MP_LIMB - prec)); + q = q * q; + r = u - q; + if (u < q) { + r += 2 * s - 1; + s --; + } + np0 <<= prec; + prec = 2 * prec; + } + sp[0] = s; + if (rp != NULL) rp[0] = r; + return (r) ? 1 : 0; +} + +#define Prec (BITS_PER_MP_LIMB >> 1) + +/* same as mpn_sqrtrem, but for size=2 and {np, 2} normalized + return cc such that {np, 2} = sp[0]^2 + cc*2^BITS+PER_MP_LIMB + rp[0] */ +mp_limb_t mpn_sqrtrem2 (mp_ptr sp, mp_ptr rp, mp_srcptr np) +{ + mp_limb_t qhl, q, u, np0; + int cc; + + np0 = np[0]; + mpn_sqrtrem1(sp, rp, np+1); + qhl = 0; + while (rp[0] >= sp[0]) { + qhl ++; + rp[0] -= sp[0]; + } + /* now rp[0] < sp[0] < 2^Prec */ + rp[0] = (rp[0] << Prec) + (np0 >> Prec); + u = 2 * sp[0]; + q = rp[0] / u; + u = rp[0] - q * u; + q += (qhl & 1) << (Prec-1); + qhl >>= 1; /* if qhl=1, necessary q=0 as qhl*2^Prec + q <= 2^Prec */ + /* now we have (initial rp[0])<<Prec + np0>>Prec = (qhl<<Prec + q) * (2sp[0]) + u */ + sp[0] = ((sp[0]+qhl) << Prec) + q; + cc = u >> Prec; + rp[0] = (u << Prec) + (np0 & (((mp_limb_t)1 << Prec) - 1)); + /* subtract q * q or qhl*2^(2*Prec) from rp */ + cc -= mpn_sub_1(rp, rp, 1, q * q) + qhl; + /* now subtract 2*q*2^Prec + 2^(2*Prec) if qhl is set */ + if (cc < 0) { + cc += (sp[0]) ? mpn_add_1(rp, rp, 1, sp[0]) : 1; + cc += mpn_add_1(rp, rp, 1, --sp[0]); + } + return cc; +} + +/* writes in {sp, n} the square root (rounded towards zero) of {np, 2n}, + and in {np, n} the low n limbs of the remainder, returns the high + limb of the remainder (which is 0 or 1). + Assumes {np, 2n} is normalized, i.e. np[2n-1] >= B/4 + where B=2^BITS_PER_MP_LIMB. +*/ +mp_limb_t mpn_dq_sqrtrem (mp_ptr sp, mp_ptr np, mp_size_t n) +{ + mp_limb_t q; /* carry out of {sp, n} */ + int c, b; /* carry out of remainder */ + mp_size_t l, h; + + if (n == 1) return mpn_sqrtrem2 (sp, np, np); + + l = n / 2; + h = n - l; + q = mpn_dq_sqrtrem (sp + l, np + 2 * l, h); + if (q) mpn_sub_n (np + 2 * l, np + 2 * l, sp + l, h); + q += mpn_divrem (sp, 0, np + l, n, sp + l, h); + c = sp[0] & 1; + mpn_rshift (sp, sp, l, 1); + sp[l-1] |= q << (BITS_PER_MP_LIMB - 1); + q >>= 1; + if (c) c = mpn_add_n (np + l, np + l, sp + l, h); + mpn_mul_n (np + n, sp, sp, l); + b = q + mpn_sub_n (np, np, np + n, 2 * l); + c -= (l == h) ? b : mpn_sub_1 (np + 2 * l, np + 2 * l, 1, b); + q = mpn_add_1 (sp + l, sp + l, h, q); + + if (c < 0) { + c += mpn_addmul_1 (np, sp, n, 2) + 2 * q; + c -= mpn_sub_1 (np, np, n, 1); + q -= mpn_sub_1 (sp, sp, n, 1); + } + + return c; +} + +/* main function */ +mp_size_t mpn_sqrtrem_new (mp_ptr sp, mp_ptr rp, mp_srcptr np, mp_size_t nn) +{ + mp_limb_t *tp, s0[1], cc; + int c, tn; + mp_size_t rn; + TMP_DECL (marker); + +#ifdef DEBUG + if (np[nn-1] == 0) { + fprintf (stderr, "Error in mpn_sqrtrem: most significant limb is zero\n"); + exit(1); + } +#endif + + count_leading_zeros(c, np[nn-1]); + + if (nn == 1 && c == 0) return mpn_sqrtrem1 (sp, rp, np); + + c = c / 2; /* we have to shift left by 2c bits to normalize {np, nn} */ + tn = (nn+1) / 2; /* 2*tn is the smallest even integer >= nn */ + + TMP_MARK (marker); + if ((nn % 2) || (c > 0)) { + tp = (mp_limb_t*) TMP_ALLOC (2 * tn * BYTES_PER_MP_LIMB); + tp[0] = 0; /* needed only when 2*tn > nn, but saves a test */ + if (c) mpn_lshift(tp + 2*tn - nn, np, nn, 2 * c); + else MPN_COPY (tp + 2*tn - nn, np, nn); + rn = mpn_dq_sqrtrem (sp, tp, tn); + /* we have 2^(2k)*N = S^2 + R where k = c + (2tn-nn)*BITS_PER_MP_LIMB/2, + thus 2^(2k)*N = (S-s0)^2 + 2*S*s0 - s0^2 + R where s0=S mod 2^k */ + c += (nn % 2) * BITS_PER_MP_LIMB / 2; /* c now represents k */ + s0[0] = sp[0] & (((mp_limb_t) 1 << c) - 1); /* S mod 2^k */ + rn += mpn_addmul_1 (tp, sp, tn, 2 * s0[0]); /* R = R + 2*s0*S */ + cc = mpn_submul_1 (tp, s0, 1, s0[0]); + rn -= (tn > 1) ? mpn_sub_1(tp + 1, tp + 1, tn - 1, cc) : cc; + mpn_rshift (sp, sp, tn, c); + tp[tn] = rn; + if (rp == NULL) rp = tp; + c = c << 1; + if (c < BITS_PER_MP_LIMB) tn++; else { tp++; c -= BITS_PER_MP_LIMB; } + if (c) mpn_rshift (rp, tp, tn, c); + else MPN_COPY(rp, tp, tn); + rn = tn; + } + else { + if (rp == NULL) + rp = (mp_limb_t*) TMP_ALLOC (nn * BYTES_PER_MP_LIMB); + if (rp != np) MPN_COPY (rp, np, nn); + rn = tn + (rp[tn] = mpn_dq_sqrtrem (sp, rp, tn)); + } + while (rn && rp[rn-1]==0) rn--; + TMP_FREE (marker); + + return rn; +} + diff --git a/mpfr/sub.c b/mpfr/sub.c index dfe755b73..4971472de 100644 --- a/mpfr/sub.c +++ b/mpfr/sub.c @@ -1,6 +1,6 @@ /* mpfr_sub -- subtract two floating-point numbers -Copyright (C) 1999 PolKA project, Inria Lorraine and Loria +Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. @@ -23,24 +23,31 @@ MA 02111-1307, USA. */ #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" +#include "mpfr-impl.h" /* #define DEBUG */ +#define ONE ((mp_limb_t) 1) + extern void mpfr_add1 _PROTO((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, - unsigned char, int)); + mp_rnd_t, int)); +mp_limb_t mpn_sub_lshift_n (mp_limb_t *, mp_limb_t *, int, int, int); +void mpfr_sub1 (mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t, int); /* put in ap[0]..ap[an-1] the value of bp[0]..bp[n-1] shifted by sh bits - to the left minus ap[0]..ap[n-1], with 0 <= sh < mp_bits_per_limb, and + to the left minus ap[0]..ap[n-1], with 0 <= sh < BITS_PER_MP_LIMB, and returns the borrow. */ mp_limb_t #if __STDC__ mpn_sub_lshift_n (mp_limb_t *ap, mp_limb_t *bp, int n, int sh, int an) #else -mpn_sub_lshift_n (ap, bp, n, sh, an) mp_limb_t *ap, *bp; int n,sh,an; +mpn_sub_lshift_n (ap, bp, n, sh, an) + mp_limb_t *ap, *bp; + int n,sh,an; #endif { - mp_limb_t c, bh; + mp_limb_t c, bh=0; /* shift b to the left */ if (sh) bh = mpn_lshift(bp, bp, n, sh); @@ -48,7 +55,7 @@ mpn_sub_lshift_n (ap, bp, n, sh, an) mp_limb_t *ap, *bp; int n,sh,an; /* shift back b to the right */ if (sh) { mpn_rshift(bp, bp, n, sh); - bp[n-1] += bh<<(mp_bits_per_limb-sh); + bp[n-1] += bh<<(BITS_PER_MP_LIMB-sh); } return c; } @@ -56,155 +63,189 @@ mpn_sub_lshift_n (ap, bp, n, sh, an) mp_limb_t *ap, *bp; int n,sh,an; /* signs of b and c differ, abs(b)>=abs(c), diff_exp>=0 */ void #if __STDC__ -mpfr_sub1(mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, unsigned char rnd_mode, int diff_exp) +mpfr_sub1 (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, + mp_rnd_t rnd_mode, int diff_exp) #else -mpfr_sub1(a, b, c, rnd_mode, diff_exp) +mpfr_sub1 (a, b, c, rnd_mode, diff_exp) mpfr_ptr a; mpfr_srcptr b; - mpfr_srcptr c; - unsigned char rnd_mode; + mpfr_srcptr c; + mp_rnd_t rnd_mode; int diff_exp; #endif { - mp_limb_t *ap, *bp, *cp, cc, c2; unsigned int an,bn,cn; + mp_limb_t *ap, *bp, *cp, cc, c2; unsigned int an, bn, cn; int sh,dif,k,cancel,cancel1,cancel2; TMP_DECL(marker); #ifdef DEBUG - printf("b= "); if (SIGN(b)>=0) putchar(' '); + printf("b= "); if (MPFR_SIGN(b)>=0) putchar(' '); mpfr_print_raw(b); putchar('\n'); - printf("c= "); if (SIGN(c)>=0) putchar(' '); + printf("c= "); if (MPFR_SIGN(c)>=0) putchar(' '); for (k=0;k<diff_exp;k++) putchar(' '); mpfr_print_raw(c); putchar('\n'); printf("b=%1.20e c=%1.20e\n",mpfr_get_d(b),mpfr_get_d(c)); #endif cancel = mpfr_cmp2(b, c); - /* we have to take into account the first (PREC(a)+cancel) bits from b */ - cancel1 = cancel/mp_bits_per_limb; cancel2 = cancel%mp_bits_per_limb; + /* we have to take into account the first (MPFR_PREC(a)+cancel) bits from b */ + cancel1 = cancel/BITS_PER_MP_LIMB; cancel2 = cancel%BITS_PER_MP_LIMB; TMP_MARK(marker); - ap = MANT(a); - bp = MANT(b); - cp = MANT(c); + ap = MPFR_MANT(a); + bp = MPFR_MANT(b); + cp = MPFR_MANT(c); if (ap == bp) { - bp = (mp_ptr) TMP_ALLOC(ABSSIZE(b) * BYTES_PER_MP_LIMB); - MPN_COPY (bp, ap, ABSSIZE(b)); + bp = (mp_ptr) TMP_ALLOC(MPFR_ABSSIZE(b) * BYTES_PER_MP_LIMB); + MPN_COPY (bp, ap, MPFR_ABSSIZE(b)); if (ap == cp) { cp = bp; } } else if (ap == cp) { - cp = (mp_ptr) TMP_ALLOC (ABSSIZE(c) * BYTES_PER_MP_LIMB); - MPN_COPY(cp, ap, ABSSIZE(c)); + cp = (mp_ptr) TMP_ALLOC (MPFR_ABSSIZE(c) * BYTES_PER_MP_LIMB); + MPN_COPY(cp, ap, MPFR_ABSSIZE(c)); } - an = (PREC(a)-1)/mp_bits_per_limb+1; /* number of significant limbs of a */ - sh = an*mp_bits_per_limb-PREC(a); /* non-significant bits in low limb */ - bn = (PREC(b)-1)/mp_bits_per_limb+1; /* number of significant limbs of b */ - cn = (PREC(c)-1)/mp_bits_per_limb + 1; - EXP(a) = EXP(b)-cancel; + an = (MPFR_PREC(a)-1)/BITS_PER_MP_LIMB+1; /* number of significant limbs of a */ + sh = an*BITS_PER_MP_LIMB-MPFR_PREC(a); /* non-significant bits in low limb */ + bn = (MPFR_PREC(b)-1)/BITS_PER_MP_LIMB+1; /* number of significant limbs of b */ + cn = (MPFR_PREC(c)-1)/BITS_PER_MP_LIMB + 1; + MPFR_EXP(a) = MPFR_EXP(b)-cancel; /* adjust sign to that of b */ - if (SIGN(a)*SIGN(b)<0) CHANGE_SIGN(a); + if (MPFR_SIGN(a)*MPFR_SIGN(b)<0) MPFR_CHANGE_SIGN(a); /* case 1: diff_exp>=prec(a), i.e. c only affects the last bit through rounding */ - dif = PREC(a)-diff_exp; + dif = MPFR_PREC(a)-diff_exp; #ifdef DEBUG - printf("PREC(a)=%d an=%u PREC(b)=%d bn=%u PREC(c)=%d diff_exp=%u dif=%d cancel=%d\n", - PREC(a),an,PREC(b),bn,PREC(c),diff_exp,dif,cancel); + printf("MPFR_PREC(a)=%d an=%u MPFR_PREC(b)=%d bn=%u MPFR_PREC(c)=%d diff_exp=%u dif=%d cancel=%d\n", + MPFR_PREC(a),an,MPFR_PREC(b),bn,MPFR_PREC(c),diff_exp,dif,cancel); #endif - if (dif<=0) { /* diff_exp>=PREC(a): c does not overlap with a */ - /* either PREC(b)<=PREC(a), and we can copy the mantissa of b directly - into that of a, or PREC(b)>PREC(a) and we have to round b-c */ - if (PREC(b)<=PREC(a)+cancel) { + if (dif<=0) { /* diff_exp>=MPFR_PREC(a): c does not overlap with a */ + /* either MPFR_PREC(b)<=MPFR_PREC(a), and we can copy the mantissa of b directly + into that of a, or MPFR_PREC(b)>MPFR_PREC(a) and we have to round b-c */ + if (MPFR_PREC(b)<=MPFR_PREC(a)+cancel) { if (cancel2) mpn_lshift(ap+(an-bn+cancel1), bp, bn-cancel1, cancel2); else MPN_COPY(ap+(an-bn+cancel1), bp, bn-cancel1); /* fill low significant limbs with zero */ MPN_ZERO(ap, an-bn+cancel1); /* now take c into account */ if (rnd_mode==GMP_RNDN) { /* to nearest */ - /* if diff_exp > PREC(a), no change */ - if (diff_exp==PREC(a)) { + /* if diff_exp > MPFR_PREC(a), no change */ + if (diff_exp==MPFR_PREC(a)) { /* if c is not zero, then as it is normalized, we have to subtract one to the lsb of a if c>1/2, or c=1/2 and lsb(a)=1 (round to even) */ - if (NOTZERO(c)) { /* c is not zero */ + if (MPFR_NOTZERO(c)) { /* c is not zero */ /* check whether mant(c)=1/2 or not */ - cc = *cp - ((mp_limb_t)1<<(mp_bits_per_limb-1)); + cc = *cp - (ONE<<(BITS_PER_MP_LIMB-1)); if (cc==0) { - bp = cp+(PREC(c)-1)/mp_bits_per_limb; + bp = cp+(MPFR_PREC(c)-1)/BITS_PER_MP_LIMB; while (cp<bp && cc==0) cc = *++cp; } - if (cc || (ap[an-1] & (mp_limb_t)1<<sh)) goto sub_one_ulp; + if (cc || (ap[an-1] & ONE<<sh)) goto sub_one_ulp; /* mant(c) > 1/2 or mant(c) = 1/2: subtract 1 iff lsb(a)=1 */ } } else if (ap[an-1]==0) { /* case b=2^n */ - ap[an-1] = (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); - EXP(a)++; + ap[an-1] = ONE << (BITS_PER_MP_LIMB-1); + MPFR_EXP(a)++; } } - else if ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || - (ISNEG(b) && rnd_mode==GMP_RNDD)) { + else if ((MPFR_ISNONNEG(b) && rnd_mode==GMP_RNDU) || + (MPFR_ISNEG(b) && rnd_mode==GMP_RNDD)) { /* round up: nothing to do */ if (ap[an-1]==0) { /* case b=2^n */ - ap[an-1] = (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); - EXP(a)++; + ap[an-1] = ONE << (BITS_PER_MP_LIMB-1); + MPFR_EXP(a)++; } } else { /* round down: subtract 1 ulp iff c<>0 */ - if (NOTZERO(c)) goto sub_one_ulp; + if (MPFR_NOTZERO(c)) goto sub_one_ulp; } } - else { /* PREC(b)>PREC(a) : we have to round b-c */ + else { /* MPFR_PREC(b)>MPFR_PREC(a) : we have to round b-c */ k=bn-an; /* first copy the 'an' most significant limbs of b to a */ MPN_COPY(ap, bp+k, an); - if (rnd_mode==GMP_RNDN) { /* to nearest */ - /* first check whether the truncated bits from b are 1/2*lsb(a) */ + { /* treat all rounding modes together */ + mp_limb_t c2old; int sign=0; long int cout=0; + if (sh) { - cc = *ap & (((mp_limb_t)1<<sh)-1); + cc = *ap & ((ONE<<sh)-1); *ap &= ~cc; /* truncate last bits */ - cc -= (mp_limb_t)1<<(sh-1); } - else /* no bit to truncate */ - cc = bp[--k] - ((mp_limb_t)1<<(mp_bits_per_limb-1)); - if ((long)cc>0) { /* suppose sizeof(long)=sizeof(mp_limb_t) */ - goto add_one_ulp; /* trunc(b)>1/2*lsb(a) -> round up */ + else cc=0; + + dif += sh; + if (dif>0) { /* c overlaps by dif bits with that last unused sh bits + from least significant limb of b */ + cn--; + c2old = cp[cn]; /* last limb from c considered */ + cout -= mpn_sub_1(&cc, &cc, 1, c2old >> (BITS_PER_MP_LIMB-dif)); } - else if (cc==0) { - while (k>1 && cc==0) cc=bp[--k]; - /* now if the truncated part of b = 1/2*lsb(a), check whether c=0 */ - if (NOTZERO(c) || (*ap & ((mp_limb_t)1<<sh))) goto sub_one_ulp; - /* if trunc(b)-c is exactly 1/2*lsb(a) : round to even lsb */ + else c2old = 0; + + /* trailing bits from b - c are -cout*2^BITS_PER_MP_LIMB + cc, + last considered limb of c is c2old, remains to take into account + its BITS_PER_MP_LIMB-dif low bits */ + + if (sh && rnd_mode==GMP_RNDN) { + if (cout>=0) { + sign = 1; + cout -= mpn_sub_1(&cc, &cc, 1, ONE<<(sh-1)); + } + else { + sign = -1; + cout += mpn_add_1(&cc, &cc, 1, ONE<<(sh-1)); + } } - /* if cc<0 : trunc(b) < 1/2*lsb(a) -> round down, i.e. do nothing */ - } - else { /* round towards infinity or zero */ - if (sh) { - cc = *ap & (((mp_limb_t)1<<sh)-1); - *ap &= ~cc; /* truncate last bits */ + + if (cout==0) { /* if cout<0, it will remain negative */ + if (dif<0) dif += BITS_PER_MP_LIMB; + while (cout==0 && (k || cn)) { + cout = cc; + cc = (k) ? bp[--k] : 0; + if (sh==0) { + if (cout>=0) { + sign = 1; + cout -= mpn_sub_1(&cc, &cc, 1, ONE << (BITS_PER_MP_LIMB-1)); + } + else { + sign = -1; + cout += mpn_add_1(&cc, &cc, 1, ONE << (BITS_PER_MP_LIMB-1)); + } + sh = 0; + } + /* next limb from c to consider is cp[cn-1], with lower part of + c2old */ + c2 = c2old << dif; + if (cn && (dif>=0)) { + cn--; + c2old = cp[cn]; + c2 += c2old >> (BITS_PER_MP_LIMB-dif); + } + else dif += BITS_PER_MP_LIMB; + cout -= mpn_sub_1(&cc, &cc, 1, c2); + } } - else cc=0; - cn--; - c2 = (dif>-sh) ? cp[cn]>>(mp_bits_per_limb-dif-sh) : 0; - while (cc==c2 && (k || cn)) { - if (k) cc = bp[--k]; - if (cn) { - c2 = cp[cn]<<(dif+sh); - if (--cn) c2 += cp[cn]>>(mp_bits_per_limb-dif-sh); - } + if (cout==0) cout=(cc!=0); + if (rnd_mode==GMP_RNDU) sign=1; + else if (rnd_mode==GMP_RNDD || rnd_mode==GMP_RNDZ) sign=-1; + /* even rounding rule: */ + if (rnd_mode==GMP_RNDN) { + if (cout==0 && (*ap & (ONE<<sh))) cout=sign; } - dif = ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || - (ISNEG(b) && rnd_mode==GMP_RNDD)); - /* round towards infinity if dif=1, towards zero otherwise */ - if (dif && cc>c2) goto add_one_ulp; - else if (dif==0 && cc<c2) goto sub_one_ulp; + else /* rounding does not depend from sign of b for GMP_RNDN */ + if (MPFR_ISNEG(b)) sign=-sign; + /* round towards infinity if sign=1, towards zero otherwise */ + if ((sign==1) && cout>0) goto add_one_ulp; + else if ((sign==-1) && cout<0) goto sub_one_ulp; } } } - else { /* case 2: diff_exp < PREC(a) : c overlaps with a by dif bits */ + else { /* case 2: diff_exp < MPFR_PREC(a) : c overlaps with a by dif bits */ /* first copy upper part of c into a (after shift) */ int overlap; dif += cancel; - k = (dif-1)/mp_bits_per_limb + 1; /* only the highest k limbs from c + k = (dif-1)/BITS_PER_MP_LIMB + 1; /* only the highest k limbs from c have to be considered */ if (k<an) { MPN_ZERO(ap+k, an-k); /* do it now otherwise ap[k] may be @@ -213,48 +254,53 @@ mpfr_sub1(a, b, c, rnd_mode, diff_exp) #ifdef DEBUG printf("cancel=%d dif=%d k=%d cn=%d sh=%d\n",cancel,dif,k,cn,sh); #endif - if (dif<=PREC(c)) { /* c has to be truncated */ - dif = dif % mp_bits_per_limb; - dif = (dif) ? mp_bits_per_limb-dif-sh : -sh; + if (dif<=MPFR_PREC(c)) { /* c has to be truncated */ + dif = dif % BITS_PER_MP_LIMB; + dif = (dif) ? BITS_PER_MP_LIMB-dif-sh : -sh; /* we have to shift by dif bits to the right */ if (dif>0) { mpn_rshift(ap, cp+(cn-k), (k<=an) ? k : an, dif); - if (k>an) ap[an-1] += cp[cn-k+an]<<(mp_bits_per_limb-dif); + if (k>an) ap[an-1] += cp[cn-k+an]<<(BITS_PER_MP_LIMB-dif); } else if (dif<0) { - cc = mpn_lshift(ap, cp+(cn-k), k, -dif); + cc = mpn_lshift(ap, cp+(cn-k), (k<=an) ? k : an, -dif); if (k<an) ap[k]=cc; /* put the non-significant bits in low limb for further rounding */ if (cn >= k+1) - ap[0] += cp[cn-k-1]>>(mp_bits_per_limb+dif); + ap[0] += cp[cn-k-1]>>(BITS_PER_MP_LIMB+dif); } - else MPN_COPY(ap, cp+(cn-k), k); + else MPN_COPY(ap, cp+(cn-k), (k<=an) ? k : an); overlap=1; } else { /* c is not truncated, but we have to fill low limbs with 0 */ - MPN_ZERO(ap, k-cn); + MPN_ZERO(ap, (k-cn<an) ? k-cn : an); overlap = cancel-diff_exp; #ifdef DEBUG printf("0:a="); mpfr_print_raw(a); putchar('\n'); printf("overlap=%d\n",overlap); #endif if (overlap>=0) { - cn -= overlap/mp_bits_per_limb; - overlap %= mp_bits_per_limb; + if (overlap/BITS_PER_MP_LIMB <= cn) + cn -= overlap/BITS_PER_MP_LIMB; + else cn=0; + overlap %= BITS_PER_MP_LIMB; /* warning: a shift of zero with mpn_lshift is not allowed */ if (overlap) { if (an<cn) { mpn_lshift(ap, cp+(cn-an), an, overlap); - ap[0] += cp[cn-an-1]>>(mp_bits_per_limb-overlap); + ap[0] += cp[cn-an-1]>>(BITS_PER_MP_LIMB-overlap); + } + else { + /* warning: mpn_lshift doesn't seem to like cn=0 */ + if (cn) mpn_lshift(ap+(an-cn), cp, cn, overlap); } - else mpn_lshift(ap+(an-cn), cp, cn, overlap); } else MPN_COPY(ap+(an-cn), cp, cn); } else { /* shift to the right by -overlap bits */ overlap = -overlap; - k = overlap/mp_bits_per_limb; - overlap = overlap % mp_bits_per_limb; + k = overlap/BITS_PER_MP_LIMB; + overlap = overlap % BITS_PER_MP_LIMB; if (overlap) cc = mpn_rshift(ap+(an-k-cn), cp, cn, overlap); else { MPN_COPY(ap+(an-k-cn), cp, cn); @@ -270,16 +316,18 @@ mpfr_sub1(a, b, c, rnd_mode, diff_exp) /* here overlap=1 iff ulp(c)<ulp(a) */ /* then put high limbs to zero */ /* now add 'an' upper limbs of b in place */ - if (PREC(b)<=PREC(a)+cancel) { int i, imax; + if (MPFR_PREC(b)<=MPFR_PREC(a)+cancel) { int i, imax; overlap += 2; /* invert low limbs */ - imax = (int)an-(int)bn+cancel1; + imax = (int)an - (int)bn + cancel1; + if (imax > (int)an) imax = an; for (i=0;i<imax;i++) ap[i] = ~ap[i]; cc = (i) ? mpn_add_1(ap, ap, i, 1) : 1; - mpn_sub_lshift_n(ap+i, bp, bn-cancel1, cancel2, an); - mpn_sub_1(ap+i, ap+i, an-i, (mp_limb_t)1-cc); + if (cancel1 < bn) mpn_sub_lshift_n(ap+i, bp, bn-cancel1, cancel2, an); + /* warning: mpn_sub_1 doesn't accept a zero length */ + if (i < an) mpn_sub_1(ap+i, ap+i, an-i, ONE-cc); } - else /* PREC(b) > PREC(a): we have to truncate b */ + else /* MPFR_PREC(b) > MPFR_PREC(a): we have to truncate b */ mpn_sub_lshift_n(ap, bp+(bn-an-cancel1), an, cancel2, an); /* remains to do the rounding */ #ifdef DEBUG @@ -289,40 +337,63 @@ mpfr_sub1(a, b, c, rnd_mode, diff_exp) if (rnd_mode==GMP_RNDN) { /* to nearest */ int kc; /* four cases: overlap = - (0) PREC(b) > PREC(a) and diff_exp+PREC(c) <= PREC(a) - (1) PREC(b) > PREC(a) and diff_exp+PREC(c) > PREC(a) - (2) PREC(b) <= PREC(a) and diff_exp+PREC(c) <= PREC(a) - (3) PREC(b) <= PREC(a) and diff_exp+PREC(c) > PREC(a) */ + (0) MPFR_PREC(b) > MPFR_PREC(a) and diff_exp+MPFR_PREC(c) <= MPFR_PREC(a) + (1) MPFR_PREC(b) > MPFR_PREC(a) and diff_exp+MPFR_PREC(c) > MPFR_PREC(a) + (2) MPFR_PREC(b) <= MPFR_PREC(a) and diff_exp+MPFR_PREC(c) <= MPFR_PREC(a) + (3) MPFR_PREC(b) <= MPFR_PREC(a) and diff_exp+MPFR_PREC(c) > MPFR_PREC(a) */ switch (overlap) { case 1: /* both b and c to round */ kc = cn-k; /* remains kc limbs from c */ k = bn-an; /* remains k limbs from b */ /* truncate last bits and store the difference with 1/2*ulp in cc */ - cc = *ap & (((mp_limb_t)1<<sh)-1); - *ap &= ~cc; /* truncate last bits */ - cc -= (mp_limb_t)1<<(sh-1); - while ((cc==0 || cc==-1) && k!=0 && kc!=0) { - kc--; - cc -= mpn_sub_1(&c2, bp+(--k), 1, (cp[kc]>>dif) + - (cp[kc+1]<<(mp_bits_per_limb-dif))); - if (cc==0 || cc==-1) cc=c2; + c2 = *ap & ((ONE<<sh)-1); + *ap &= ~c2; /* truncate last bits */ + cc = -mpn_sub_1(&c2, &c2, 1, ONE<<(sh-1)); + if (cc==0) cc=c2; + /* loop invariant: cc*2^BITS_PER_MP_LIMB+c2 is the current difference + between b - 1/2*ulp(a) and c shifted by dif bits to the right. + cc > 0 ==> add one ulp + cc < 0 ==> truncate + cc = 0 ==> go to next limb + */ + while ((cc==0) && (k>=0 || kc>=0)) { + k--; kc--; + if (k>=0) { + if (kc>=0) cc -= mpn_sub_1(&c2, bp+k, 1, (cp[kc]>>dif) + + (cp[kc+1]<<(BITS_PER_MP_LIMB-dif))); + else /* don't forget last right chunck from c */ + cc -= mpn_sub_1(&c2, bp+k, 1, cp[0]<<(BITS_PER_MP_LIMB-dif)); + } + else { /* no more limb from b */ + /* warning: if k was 0, kc can be negative here */ + if ((kc+1>=0) && (cp[kc+1]<<(BITS_PER_MP_LIMB-dif))) cc=-1; + else while ((cc==0) && (kc>=0)) { + if (cp[kc]) cc=-1; + kc--; + } + } + if (cc==0) cc=c2; } - if ((long)cc>0) goto add_one_ulp; - else if ((long)cc<-1) goto end_of_sub; /* the carry can be at most 1 */ - else if (kc==0) goto round_b; + /* cc should either 0 or -1 here */ + if ((int)cc>0) goto add_one_ulp; + else if ((int)cc<0) goto end_of_sub; /* carry can be at most 1 */ + else /* cc=0 */ + { + if (c2 || (*ap & (ONE<<sh))) goto add_one_ulp; + else goto end_of_sub; + } /* else round c: go through */ case 3: /* only c to round */ bp=cp; k=cn-k; goto to_nearest; case 0: /* only b to round */ - round_b: k=bn-an; dif=0; goto to_nearest; /* otherwise the result is exact: nothing to do */ } } - else if ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || - (ISNEG(b) && rnd_mode==GMP_RNDD)) { - cc = *ap & (((mp_limb_t)1<<sh)-1); + else if ((MPFR_ISNONNEG(b) && rnd_mode==GMP_RNDU) || + (MPFR_ISNEG(b) && rnd_mode==GMP_RNDD)) { + cc = *ap & ((ONE<<sh)-1); *ap &= ~cc; /* truncate last bits */ if (cc) goto add_one_ulp; /* will happen most of the time */ else { /* same four cases too */ @@ -331,11 +402,11 @@ mpfr_sub1(a, b, c, rnd_mode, diff_exp) { case 1: /* both b and c to round */ k = bn-an; /* remains k limbs from b */ - dif = diff_exp % mp_bits_per_limb; + dif = diff_exp % BITS_PER_MP_LIMB; while (cc==0 && k!=0 && kc!=0) { kc--; cc = bp[--k] - (cp[kc]>>dif); - if (dif) cc -= (cp[kc+1]<<(mp_bits_per_limb-dif)); + if (dif) cc -= (cp[kc+1]<<(BITS_PER_MP_LIMB-dif)); } if (cc) goto add_one_ulp; else if (kc==0) goto round_b2; @@ -343,7 +414,7 @@ mpfr_sub1(a, b, c, rnd_mode, diff_exp) case 3: /* only c to round: nothing to do */ /* while (kc) if (cp[--kc]) goto add_one_ulp; */ /* if dif>0 : remains to check last dif bits from c */ - /* if (dif>0 && (cp[0]<<(mp_bits_per_limb-dif))) goto add_one_ulp; */ + /* if (dif>0 && (cp[0]<<(BITS_PER_MP_LIMB-dif))) goto add_one_ulp; */ break; case 0: /* only b to round */ round_b2: @@ -354,22 +425,41 @@ mpfr_sub1(a, b, c, rnd_mode, diff_exp) } } /* else round to zero: remove 1 ulp if neglected bits from b-c are < 0 */ - else { - cc = *ap & (((mp_limb_t)1<<sh)-1); + else { int kc=cn-k; + cc = *ap & ((ONE<<sh)-1); *ap &= ~cc; if (cc==0) { /* otherwise neglected difference cannot be < 0 */ /* take into account bp[0]..bp[bn-cancel1-1] shifted by cancel2 to left and cp[0]..cp[cn-k-1] shifted by dif bits to right */ - switch (overlap) { + switch (overlap) { case 0: case 2: break; /* c is not truncated ==> no borrow */ case 1: /* both b and c are truncated */ + k = bn-an; /* remains k limbs from b */ + dif = diff_exp % BITS_PER_MP_LIMB; + while (k!=0 && kc!=0) { + kc--; + cc = cp[kc]>>dif; + if (dif) cc += cp[kc+1]<<(BITS_PER_MP_LIMB-dif); + k--; + if (bp[k]>cc) goto end_of_sub; + else if (bp[k]<cc) goto sub_one_ulp; + } + if (k==0) { /* is the remainder from c zero or not? */ + while (kc!=0) { + kc--; + cc = cp[kc]>>dif; + if (dif) cc += cp[kc+1]<<(BITS_PER_MP_LIMB-dif); + if (cc) goto sub_one_ulp; + } + if (cp[0]<<(BITS_PER_MP_LIMB-dif)) goto sub_one_ulp; + } break; case 3: /* only c is truncated */ cn -= k; /* take into account cp[0]..cp[cn-1] shifted by dif bits to the right */ - cc = (dif>0) ? cp[cn]<<(mp_bits_per_limb-dif) : 0; + cc = (dif>0) ? cp[cn]<<(BITS_PER_MP_LIMB-dif) : 0; while (cc==0 && cn>0) cc = cp[--cn]; if (cc) goto sub_one_ulp; break; @@ -379,18 +469,18 @@ mpfr_sub1(a, b, c, rnd_mode, diff_exp) } goto end_of_sub; - to_nearest: /* 0 <= sh < mp_bits_per_limb : number of bits of a to truncate + to_nearest: /* 0 <= sh < BITS_PER_MP_LIMB : number of bits of a to truncate bp[k] : last significant limb from b */ #ifdef DEBUG mpfr_print_raw(a); putchar('\n'); #endif if (sh) { - cc = *ap & (((mp_limb_t)1<<sh)-1); + cc = *ap & ((ONE<<sh)-1); *ap &= ~cc; /* truncate last bits */ - c2 = (mp_limb_t)1<<(sh-1); + c2 = ONE<<(sh-1); } else /* no bit to truncate */ - { if (k) cc = bp[--k]; else cc = 0; c2 = (mp_limb_t)1<<(mp_bits_per_limb-1); } + { if (k) cc = bp[--k]; else cc = 0; c2 = ONE<<(BITS_PER_MP_LIMB-1); } #ifdef DEBUG printf("cc=%lu c2=%lu k=%u\n",cc,c2,k); #endif @@ -401,28 +491,28 @@ mpfr_print_raw(a); putchar('\n'); printf("cc=%lu\n",cc); #endif /* special case of rouding c shifted to the right */ - if (cc==0 && dif>0) cc=bp[0]<<(mp_bits_per_limb-dif); + if (cc==0 && dif>0) cc=bp[0]<<(BITS_PER_MP_LIMB-dif); /* now if the truncated part of b = 1/2*lsb(a), check whether c=0 */ if (bp!=cp) { - if (cc || (*ap & ((mp_limb_t)1<<sh))) goto add_one_ulp; + if (cc || (*ap & (ONE<<sh))) goto add_one_ulp; } else { /* subtract: if cc>0, do nothing */ - if (cc==0 && (*ap & ((mp_limb_t)1<<sh))) goto add_one_ulp; + if (cc==0 && (*ap & (ONE<<sh))) goto add_one_ulp; } } goto end_of_sub; sub_one_ulp: - cc = mpn_sub_1(ap, ap, an, (mp_limb_t)1<<sh); + cc = mpn_sub_1(ap, ap, an, ONE<<sh); goto end_of_sub; add_one_ulp: /* add one unit in last place to a */ - cc = mpn_add_1(ap, ap, an, (mp_limb_t)1<<sh); + cc = mpn_add_1(ap, ap, an, ONE<<sh); end_of_sub: #ifdef DEBUG -printf("b-c="); if (SIGN(a)>0) putchar(' '); mpfr_print_raw(a); putchar('\n'); +printf("b-c="); if (MPFR_SIGN(a)>0) putchar(' '); mpfr_print_raw(a); putchar('\n'); #endif TMP_FREE(marker); return; @@ -430,43 +520,78 @@ printf("b-c="); if (SIGN(a)>0) putchar(' '); mpfr_print_raw(a); putchar('\n'); void #if __STDC__ -mpfr_sub(mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, unsigned char rnd_mode) +mpfr_sub (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mp_rnd_t rnd_mode) #else -mpfr_sub(a, b, c, rnd_mode) - mpfr_ptr a; +mpfr_sub (a, b, c, rnd_mode) + mpfr_ptr a; mpfr_srcptr b; - mpfr_srcptr c; - unsigned char rnd_mode; + mpfr_srcptr c; + mp_rnd_t rnd_mode; #endif { int diff_exp; - if (FLAG_NAN(b) || FLAG_NAN(c)) { SET_NAN(a); return; } + if (MPFR_IS_NAN(b) || MPFR_IS_NAN(c)) { + MPFR_SET_NAN(a); + return; + } + + MPFR_CLEAR_NAN(a); + + if (MPFR_IS_INF(b)) + { + if (MPFR_IS_INF(c)) + { + if (MPFR_SIGN(b) != MPFR_SIGN(c)) + { + MPFR_SET_INF(a); + if (MPFR_SIGN(a) != MPFR_SIGN(b)) { MPFR_CHANGE_SIGN(a); } + } + else + MPFR_SET_NAN(a); + } + else + { + MPFR_SET_INF(a); + if (MPFR_SIGN(b) != MPFR_SIGN(a)) { MPFR_CHANGE_SIGN(a); } + } + return; + } + else + if (MPFR_IS_INF(c)) + { + MPFR_SET_INF(a); + if (MPFR_SIGN(c) == MPFR_SIGN(a)) { MPFR_CHANGE_SIGN(a); } + return; + } + + if (!MPFR_NOTZERO(b)) { mpfr_neg(a, c, rnd_mode); return; } + if (!MPFR_NOTZERO(c)) { mpfr_set(a, b, rnd_mode); return; } - if (!NOTZERO(b)) { mpfr_neg(a, c, rnd_mode); return; } - if (!NOTZERO(c)) { mpfr_set(a, b, rnd_mode); return; } + MPFR_CLEAR_INF(a); - diff_exp = EXP(b)-EXP(c); - if (SIGN(b) == SIGN(c)) { /* signs are equal, it's a real subtraction */ + diff_exp = MPFR_EXP(b)-MPFR_EXP(c); + if (MPFR_SIGN(b) == MPFR_SIGN(c)) { + /* signs are equal, it's a real subtraction */ if (diff_exp<0) { /* exchange rounding modes towards +/- infinity */ if (rnd_mode==GMP_RNDU) rnd_mode=GMP_RNDD; else if (rnd_mode==GMP_RNDD) rnd_mode=GMP_RNDU; mpfr_sub1(a, c, b, rnd_mode, -diff_exp); - CHANGE_SIGN(a); + MPFR_CHANGE_SIGN(a); } else if (diff_exp>0) mpfr_sub1(a, b, c, rnd_mode, diff_exp); else { /* diff_exp=0 */ diff_exp = mpfr_cmp3(b,c,1); /* if b>0 and diff_exp>0 or b<0 and diff_exp<0: abs(b) > abs(c) */ - if (diff_exp==0) SET_ZERO(a); - else if (diff_exp*SIGN(b)>0) mpfr_sub1(a, b, c, rnd_mode, 0); + if (diff_exp==0) MPFR_SET_ZERO(a); + else if (diff_exp*MPFR_SIGN(b)>0) mpfr_sub1(a, b, c, rnd_mode, 0); else { /* exchange rounding modes towards +/- infinity */ if (rnd_mode==GMP_RNDU) rnd_mode=GMP_RNDD; else if (rnd_mode==GMP_RNDD) rnd_mode=GMP_RNDU; mpfr_sub1(a, c, b, rnd_mode, 0); - CHANGE_SIGN(a); + MPFR_CHANGE_SIGN(a); } } } @@ -476,7 +601,7 @@ mpfr_sub(a, b, c, rnd_mode) if (rnd_mode==GMP_RNDU) rnd_mode=GMP_RNDD; else if (rnd_mode==GMP_RNDD) rnd_mode=GMP_RNDU; mpfr_add1(a, c, b, rnd_mode, -diff_exp); - CHANGE_SIGN(a); + MPFR_CHANGE_SIGN(a); } else mpfr_add1(a, b, c, rnd_mode, diff_exp); } diff --git a/mpfr/sub_ui.c b/mpfr/sub_ui.c new file mode 100644 index 000000000..4b64caff7 --- /dev/null +++ b/mpfr/sub_ui.c @@ -0,0 +1,54 @@ +/* mpfr_sub_ui -- subtract a floating-point number and a machine integer + +Copyright (C) 2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +void +#if __STDC__ +mpfr_sub_ui (mpfr_ptr y, mpfr_srcptr x, unsigned long int u, mp_rnd_t rnd_mode) +#else +mpfr_sub_ui (y, x, u, rnd_mode) + mpfr_ptr y; + mpfr_srcptr x; + unsigned long int u; + mp_rnd_t rnd_mode; +#endif +{ + mpfr_t uu; + mp_limb_t up[1]; + unsigned long cnt; + + if (u) { /* if u=0, do nothing */ + MPFR_INIT1(up, uu, BITS_PER_MP_LIMB, 1); + count_leading_zeros(cnt, (mp_limb_t) u); + *up = (mp_limb_t) u << cnt; + MPFR_EXP(uu) = BITS_PER_MP_LIMB-cnt; + + mpfr_sub (y, x, uu, rnd_mode); + } + else + mpfr_set (y, x, rnd_mode); +} diff --git a/mpfr/swap.c b/mpfr/swap.c new file mode 100644 index 000000000..18b6c981d --- /dev/null +++ b/mpfr/swap.c @@ -0,0 +1,59 @@ +/* mpfr_swap (U, V) -- Swap U and V. + +Copyright (C) 1997, 1998, 2000 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the GNU MP Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +void +#if __STDC__ +mpfr_swap (mpfr_ptr u, mpfr_ptr v) +#else +mpfr_swap (u, v) + mpfr_ptr u; + mpfr_ptr v; +#endif +{ + mp_ptr up, vp; + mp_size_t usize, vsize; + mp_prec_t uprec, vprec; + mp_exp_t uexp, vexp; + + uprec = MPFR_PREC(u); + vprec = MPFR_PREC(v); + MPFR_PREC(v) = uprec; + MPFR_PREC(u) = vprec; + + usize = MPFR_SIZE(u); + vsize = MPFR_SIZE(v); + MPFR_SIZE(v) = usize; + MPFR_SIZE(u) = vsize; + + uexp = MPFR_EXP(u); + vexp = MPFR_EXP(v); + MPFR_EXP(v) = uexp; + MPFR_EXP(u) = vexp; + + up = MPFR_MANT(u); + vp = MPFR_MANT(v); + MPFR_MANT(v) = up; + MPFR_MANT(u) = vp; +} diff --git a/mpfr/trunc.c b/mpfr/trunc.c new file mode 100644 index 000000000..b6f924d35 --- /dev/null +++ b/mpfr/trunc.c @@ -0,0 +1,185 @@ +/* mpf_trunc, mpf_floor, mpf_ceil -- Assign a float from another float while + rounding it to an integer. + +Copyright (C) 1997, 1998 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the GNU MP Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +#ifdef OPERATION_floor +#define _MPFR_FLOOR_OR_CEIL +#define FUNC_NAME mpfr_floor +#define MPFR_FLOOR 1 +#define MPFR_CEIL 0 +#endif + +#ifdef OPERATION_ceil +#define _MPFR_FLOOR_OR_CEIL +#define FUNC_NAME mpfr_ceil +#define MPFR_CEIL 1 +#define MPFR_FLOOR 0 +#endif + +#ifdef OPERATION_trunc +#undef FUNC_NAME +#define FUNC_NAME mpfr_trunc +#endif + +#if 0 +#ifdef _MPFR_FLOOR_OR_CEIL +static int +mpn_zero_p (p, n) + mp_ptr p; + mp_size_t n; +{ + mp_size_t i; + + for (i = 0; i < n; i++) + { + if (p[i] != 0) + return 0; + } + + return 1; +} +#endif +#endif + +void +#if __STDC__ +FUNC_NAME (mpfr_ptr r, mpfr_srcptr u) +#else +FUNC_NAME (r, u) + mpfr_ptr r; + mpfr_srcptr u; +#endif +{ + mp_ptr rp, up; + mp_size_t asize; + mp_size_t prec, rw; +#ifdef _MPFR_FLOOR_OR_CEIL + mp_size_t ignored_n; +#endif + mp_exp_t exp; + int signu; long diff; + + if (MPFR_IS_NAN(u)) { + MPFR_SET_NAN(r); + return; + } + + MPFR_CLEAR_NAN(r); + + if (MPFR_IS_INF(u)) { + MPFR_SET_INF(r); + if (MPFR_SIGN(r) != MPFR_SIGN(u)) MPFR_CHANGE_SIGN(r); + return; + } + + MPFR_CLEAR_INF(r); + + if (!MPFR_NOTZERO(u)) { + MPFR_SET_ZERO(r); + return; + } + + signu = MPFR_SIZE(u); + rp = MPFR_MANT(r); + exp = MPFR_EXP(u); + prec = (MPFR_PREC(r) - 1)/BITS_PER_MP_LIMB + 1; + + /* Single out the case where |u| < 1. */ + if (exp <= 0) + { +#ifdef _MPFR_FLOOR_OR_CEIL + if ((MPFR_FLOOR && signu < 0) || (MPFR_CEIL && signu >= 0)) + { + rp[prec-1] = (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); + MPN_ZERO(rp, prec-1); + /* sign of result is that of u */ + if (MPFR_SIGN(r) * signu < 0) MPFR_CHANGE_SIGN(r); + MPFR_EXP(r) = 1; + return; + } +#endif + MPFR_SET_ZERO(r); + return; + } + + asize = (MPFR_PREC(u) - 1)/BITS_PER_MP_LIMB + 1; + +#ifdef _MPFR_FLOOR_OR_CEIL + ignored_n = 0; +#endif + up = MPFR_MANT(u); + + if (asize > prec) + { +#ifdef _MPFR_FLOOR_OR_CEIL + ignored_n = asize - prec; +#endif + up += asize - prec; + asize = prec; + } + + diff = BITS_PER_MP_LIMB * asize - exp; + if (diff > 0) + { + diff = diff/BITS_PER_MP_LIMB; +#ifdef _MPFR_FLOOR_OR_CEIL + ignored_n += diff; +#endif + up += diff; + asize -= diff; + } + + /* number of non significant bits in low limb of r */ + rw = asize * BITS_PER_MP_LIMB - exp; + MPN_ZERO(rp, prec-asize); + rp += prec-asize; + +#ifdef _MPFR_FLOOR_OR_CEIL + if (((MPFR_FLOOR && signu < 0) || (MPFR_CEIL && signu >= 0)) + && (!mpn_zero_p (up - ignored_n, ignored_n) + || (rw && (up[0] << (BITS_PER_MP_LIMB-rw))))) + { + mp_limb_t cy; + cy = mpn_add_1 (rp, up, asize, (mp_limb_t) 1 << rw); + if (cy != 0) + { + mpn_rshift(rp, rp, asize, 1); + rp[asize-1] = (mp_limb_t) 1 << (BITS_PER_MP_LIMB - 1); + exp++; + } + } + else +#endif + MPN_COPY (rp, up, asize); + + /* Put to 0 the remaining bits */ + if (rw) rp[0] &= + ~((((mp_limb_t)1)<<rw) - (mp_limb_t)1); + + MPFR_EXP(r) = exp; + if (MPFR_SIGN(r) * signu < 0) MPFR_CHANGE_SIGN(r); +} diff --git a/mpfr/ui_div.c b/mpfr/ui_div.c new file mode 100644 index 000000000..712d00dd9 --- /dev/null +++ b/mpfr/ui_div.c @@ -0,0 +1,74 @@ +/* mpfr_ui_div -- divide a machine integer by a floating-point number + +Copyright (C) 2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +void +#if __STDC__ +mpfr_ui_div (mpfr_ptr y, unsigned long int u, mpfr_srcptr x, mp_rnd_t rnd_mode) +#else +mpfr_ui_div (y, u, x, rnd_mode) + mpfr_ptr y; + unsigned long int u; + mpfr_srcptr x; + mp_rnd_t rnd_mode; +#endif +{ + mpfr_t uu; + mp_limb_t up[1]; + unsigned long cnt; + + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(y); + return; + } + + MPFR_CLEAR_NAN(y); + + if (MPFR_IS_INF(x)) + { + MPFR_CLEAR_INF(y); + MPFR_SET_ZERO(y); + if (MPFR_SIGN(x) != MPFR_SIGN(y)) MPFR_CHANGE_SIGN(y); + return; + } + + MPFR_CLEAR_INF(y); + + if (u) { + MPFR_INIT1(up, uu, BITS_PER_MP_LIMB, 1); + count_leading_zeros(cnt, (mp_limb_t) u); + *up = (mp_limb_t) u << cnt; + MPFR_EXP(uu) = BITS_PER_MP_LIMB-cnt; + + mpfr_div(y, uu, x, rnd_mode); + } + else { + if (MPFR_IS_ZERO(x)) MPFR_SET_NAN(y); /* 0/0 */ + else MPFR_SET_ZERO(y); /* if u=0, then set y to 0 */ + } +} diff --git a/mpfr/ui_sub.c b/mpfr/ui_sub.c new file mode 100644 index 000000000..8bc560cd6 --- /dev/null +++ b/mpfr/ui_sub.c @@ -0,0 +1,68 @@ +/* mpfr_ui_sub -- divide a machine integer by a floating-point number + +Copyright (C) 2000 Free Software Foundation. + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +void +#if __STDC__ +mpfr_ui_sub (mpfr_ptr y, unsigned long int u, mpfr_srcptr x, mp_rnd_t rnd_mode) +#else +mpfr_ui_sub (y, u, x, rnd_mode) + mpfr_ptr y; + unsigned long int u; + mpfr_srcptr x; + mp_rnd_t rnd_mode; +#endif +{ + mpfr_t uu; + mp_limb_t up[1]; + unsigned long cnt; + + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(y); + return; + } + + MPFR_CLEAR_NAN(y); + + if (MPFR_IS_INF(x)) + { + MPFR_SET_INF(y); + if (MPFR_SIGN(x) == MPFR_SIGN(y)) MPFR_CHANGE_SIGN(y); + return; + } + + if (u) { + MPFR_INIT1(up, uu, BITS_PER_MP_LIMB, 1); + count_leading_zeros(cnt, (mp_limb_t) u); + *up = (mp_limb_t) u << cnt; + MPFR_EXP(uu) = BITS_PER_MP_LIMB-cnt; + + mpfr_sub (y, uu, x, rnd_mode); + } + else mpfr_neg (y, x, rnd_mode); /* if u=0, then set y to -x */ +} diff --git a/mpfr/urandomb.c b/mpfr/urandomb.c new file mode 100644 index 000000000..02d909824 --- /dev/null +++ b/mpfr/urandomb.c @@ -0,0 +1,78 @@ +/* mpfr_urandomb (rop, state, nbits) -- Generate a uniform pseudorandom + real number between 0 (inclusive) and 1 (exclusive) of size NBITS, + using STATE as the random state previously initialized by a call to + gmp_randinit(). + +Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the GNU MP Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +void +#if __STDC__ +mpfr_urandomb (mpfr_ptr rop, gmp_randstate_t rstate) +#else +mpfr_urandomb (rop, rstate) + mpfr_ptr rop; + gmp_randstate_t rstate; +#endif +{ + mp_ptr rp; + mp_size_t nlimbs; + mp_exp_t exp; + unsigned long cnt, nbits; + + MPFR_CLEAR_FLAGS(rop); + + rp = MPFR_MANT(rop); + nbits = MPFR_PREC(rop); + nlimbs = (nbits + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB; + + _gmp_rand (rp, rstate, nbits); + + /* If nbits isn't a multiple of BITS_PER_MP_LIMB, shift up. */ + if (nlimbs != 0) + { + if (nbits % BITS_PER_MP_LIMB != 0) + mpn_lshift (rp, rp, nlimbs, + BITS_PER_MP_LIMB - nbits % BITS_PER_MP_LIMB); + } + + exp = 0; + while (nlimbs != 0 && rp[nlimbs - 1] == 0) + { + nlimbs--; + exp--; + } + + count_leading_zeros (cnt, rp[nlimbs - 1]); + if (cnt) mpn_lshift (rp, rp, nlimbs, cnt); + exp -= cnt; + + cnt = nlimbs*BITS_PER_MP_LIMB - nbits; + /* cnt is the number of non significant bits in the low limb */ + rp[0] &= ~((((mp_limb_t) 1) << cnt) - 1); + + MPFR_EXP (rop) = exp; +} |