diff options
author | Kevin Ryde <user42@zip.com.au> | 2001-11-30 01:39:14 +0100 |
---|---|---|
committer | Kevin Ryde <user42@zip.com.au> | 2001-11-30 01:39:14 +0100 |
commit | a30a00c444bb3d2b90c14b488c66fafa7df3c631 (patch) | |
tree | 8a7ce3e110086e9371072f0c8a7e5151f60f290b | |
parent | 1778ba984df3d10a3a95e58ce8990fa0b431c3a3 (diff) | |
download | gmp-a30a00c444bb3d2b90c14b488c66fafa7df3c631.tar.gz |
* mpfr: Update to 2001-11-16. Patch TMP handling of agm.c and sqrt.c,
separate .c files for floor and ceil.
-rw-r--r-- | mpfr/acosh.c | 134 | ||||
-rw-r--r-- | mpfr/add.c | 506 | ||||
-rw-r--r-- | mpfr/add1.c | 548 | ||||
-rw-r--r-- | mpfr/add_ui.c | 57 | ||||
-rw-r--r-- | mpfr/add_ulp.c | 55 | ||||
-rw-r--r-- | mpfr/agm.c | 83 | ||||
-rw-r--r-- | mpfr/asin.c | 181 | ||||
-rw-r--r-- | mpfr/asinh.c | 136 | ||||
-rw-r--r-- | mpfr/atan.c | 261 | ||||
-rw-r--r-- | mpfr/atanh.c | 142 | ||||
-rw-r--r-- | mpfr/ceil.c | 2 | ||||
-rw-r--r-- | mpfr/clear.c | 15 | ||||
-rw-r--r-- | mpfr/cmp.c | 255 | ||||
-rw-r--r-- | mpfr/cmp2.c | 183 | ||||
-rw-r--r-- | mpfr/cmp_abs.c | 72 | ||||
-rw-r--r-- | mpfr/cmp_ui.c | 33 | ||||
-rw-r--r-- | mpfr/copysign.c | 76 | ||||
-rw-r--r-- | mpfr/cos.c | 137 | ||||
-rw-r--r-- | mpfr/cosh.c | 126 | ||||
-rw-r--r-- | mpfr/dim.c | 55 | ||||
-rw-r--r-- | mpfr/div.c | 602 | ||||
-rw-r--r-- | mpfr/div_2exp.c | 29 | ||||
-rw-r--r-- | mpfr/div_ui.c | 203 | ||||
-rw-r--r-- | mpfr/dump.c | 32 | ||||
-rw-r--r-- | mpfr/eq.c | 28 | ||||
-rw-r--r-- | mpfr/euler.c | 171 | ||||
-rw-r--r-- | mpfr/exceptions.c | 230 | ||||
-rw-r--r-- | mpfr/exp.c | 119 | ||||
-rw-r--r-- | mpfr/exp2.c | 465 | ||||
-rw-r--r-- | mpfr/exp3.c | 94 | ||||
-rw-r--r-- | mpfr/exp_2.c | 368 | ||||
-rw-r--r-- | mpfr/expm1.c | 116 | ||||
-rw-r--r-- | mpfr/extract.c | 17 | ||||
-rw-r--r-- | mpfr/factorial.c | 104 | ||||
-rw-r--r-- | mpfr/floor.c | 2 | ||||
-rw-r--r-- | mpfr/fma.c | 200 | ||||
-rw-r--r-- | mpfr/generic.c | 89 | ||||
-rw-r--r-- | mpfr/get_str.c | 70 | ||||
-rw-r--r-- | mpfr/gmp_op.c | 122 | ||||
-rw-r--r-- | mpfr/hypot.c | 134 | ||||
-rw-r--r-- | mpfr/init.c | 43 | ||||
-rw-r--r-- | mpfr/init2.c | 46 | ||||
-rw-r--r-- | mpfr/inp_str.c | 22 | ||||
-rw-r--r-- | mpfr/isinf.c | 31 | ||||
-rw-r--r-- | mpfr/isinteger.c | 49 | ||||
-rw-r--r-- | mpfr/isnan.c | 22 | ||||
-rw-r--r-- | mpfr/isnum.c | 31 | ||||
-rw-r--r-- | mpfr/log.c | 72 | ||||
-rw-r--r-- | mpfr/log1p.c | 134 | ||||
-rw-r--r-- | mpfr/log2.c | 100 | ||||
-rw-r--r-- | mpfr/log_base_10.c | 147 | ||||
-rw-r--r-- | mpfr/log_base_2.c | 151 | ||||
-rw-r--r-- | mpfr/minmax.c | 81 | ||||
-rw-r--r-- | mpfr/mpz_set_fr.c | 38 | ||||
-rw-r--r-- | mpfr/mul.c | 134 | ||||
-rw-r--r-- | mpfr/mul_2exp.c | 31 | ||||
-rw-r--r-- | mpfr/mul_ui.c | 136 | ||||
-rw-r--r-- | mpfr/neg.c | 31 | ||||
-rw-r--r-- | mpfr/out_str.c | 68 | ||||
-rw-r--r-- | mpfr/pi.c | 31 | ||||
-rw-r--r-- | mpfr/pow.c | 321 | ||||
-rw-r--r-- | mpfr/pow_si.c | 160 | ||||
-rw-r--r-- | mpfr/pow_ui.c | 106 | ||||
-rw-r--r-- | mpfr/print_raw.c | 31 | ||||
-rw-r--r-- | mpfr/print_rnd_mode.c | 36 | ||||
-rw-r--r-- | mpfr/random.c | 27 | ||||
-rw-r--r-- | mpfr/random2.c | 28 | ||||
-rw-r--r-- | mpfr/reldiff.c | 46 | ||||
-rw-r--r-- | mpfr/rnd_mode.c | 17 | ||||
-rw-r--r-- | mpfr/round.c | 507 | ||||
-rw-r--r-- | mpfr/save_expo.c | 62 | ||||
-rw-r--r-- | mpfr/set.c | 83 | ||||
-rw-r--r-- | mpfr/set_d.c | 164 | ||||
-rw-r--r-- | mpfr/set_dfl_prec.c | 15 | ||||
-rw-r--r-- | mpfr/set_f.c | 67 | ||||
-rw-r--r-- | mpfr/set_prc_raw.c | 17 | ||||
-rw-r--r-- | mpfr/set_prec.c | 31 | ||||
-rw-r--r-- | mpfr/set_q.c | 52 | ||||
-rw-r--r-- | mpfr/set_rnd.c | 15 | ||||
-rw-r--r-- | mpfr/set_si.c | 72 | ||||
-rw-r--r-- | mpfr/set_str.c | 38 | ||||
-rw-r--r-- | mpfr/set_str_raw.c | 26 | ||||
-rw-r--r-- | mpfr/set_ui.c | 85 | ||||
-rw-r--r-- | mpfr/set_z.c | 29 | ||||
-rw-r--r-- | mpfr/sin.c | 78 | ||||
-rw-r--r-- | mpfr/sinh.c | 135 | ||||
-rw-r--r-- | mpfr/sqrt.c | 123 | ||||
-rw-r--r-- | mpfr/sqrt_ui.c | 54 | ||||
-rw-r--r-- | mpfr/sub.c | 672 | ||||
-rw-r--r-- | mpfr/sub1.c | 406 | ||||
-rw-r--r-- | mpfr/sub_ui.c | 44 | ||||
-rw-r--r-- | mpfr/swap.c | 16 | ||||
-rw-r--r-- | mpfr/tan.c | 82 | ||||
-rw-r--r-- | mpfr/tanh.c | 150 | ||||
-rw-r--r-- | mpfr/trunc.c | 79 | ||||
-rw-r--r-- | mpfr/ui_div.c | 61 | ||||
-rw-r--r-- | mpfr/ui_pow.c | 119 | ||||
-rw-r--r-- | mpfr/ui_pow_ui.c | 80 | ||||
-rw-r--r-- | mpfr/ui_sub.c | 40 | ||||
-rw-r--r-- | mpfr/urandomb.c | 26 |
100 files changed, 8148 insertions, 3702 deletions
diff --git a/mpfr/acosh.c b/mpfr/acosh.c new file mode 100644 index 000000000..6953b9b37 --- /dev/null +++ b/mpfr/acosh.c @@ -0,0 +1,134 @@ +/* mpfr_acosh -- Inverse Hyperbolic Cosine of Unsigned Integer Number + +Copyright (C) 2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + + /* The computation of acosh is done by + + acosh= ln(x+sqrt(x-1)*sqrt(x+1)) + */ + +int +mpfr_acosh (mpfr_ptr y, mpfr_srcptr x , mp_rnd_t rnd_mode) +{ + + int inexact =0; + int comp; + + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(y); + return 1; + } + + comp=mpfr_cmp_ui(x,1); + + if(comp < 0) + { + MPFR_SET_NAN(y); + return(1); + } + MPFR_CLEAR_NAN(y); + + if(comp == 0) + { + MPFR_SET_ZERO(y); /* acosh(1) = 0 */ + return(0); + } + + if (MPFR_IS_INF(x)) + { + MPFR_SET_INF(y); + if (MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN(y); + return 1; + } + + MPFR_CLEAR_INF(y); + + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t t, te,ti; + + /* Declaration of the size variable */ + mp_prec_t Nx = MPFR_PREC(x); /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ + + mp_prec_t Nt; /* Precision of the intermediary variable */ + int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt=Nt+4+_mpfr_ceil_log2(Nt); + + /* initialise of intermediary variable */ + mpfr_init(t); + mpfr_init(te); + mpfr_init(ti); + + /* First computation of cosh */ + do { + + /* reactualisation of the precision */ + mpfr_set_prec(t,Nt); + mpfr_set_prec(te,Nt); + mpfr_set_prec(ti,Nt); + + /* compute acosh */ + mpfr_mul(te,x,x,GMP_RNDD); /* (x^2) */ + mpfr_sub_ui(ti,te,1,GMP_RNDD); /* (x^2-1) */ + mpfr_sqrt(t,ti,GMP_RNDN); /* sqrt(x^2-1) */ + mpfr_add(t,t,x,GMP_RNDN); /* sqrt(x^2-1)+x */ + mpfr_log(t,t,GMP_RNDN); /* ln(sqrt(x^2-1)+x)*/ + + /* estimation of the error see- algorithms.ps*/ + /*err=Nt-_mpfr_ceil_log2(0.5+pow(2,2-MPFR_EXP(t))+pow(2,1+MPFR_EXP(te)-MPFR_EXP(ti)-MPFR_EXP(t)));*/ + err=Nt-(-1+2*MAX(2+MAX(2-MPFR_EXP(t),1+MPFR_EXP(te)-MPFR_EXP(ti)-MPFR_EXP(t)),0)); + + /* actualisation of the precision */ + Nt += 10; + + } while ((err<0) ||!mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny)); + + inexact = mpfr_set(y,t,rnd_mode); + + mpfr_clear(t); + mpfr_clear(ti); + mpfr_clear(te); + } + return inexact; +} + + + + + + + + + + + diff --git a/mpfr/add.c b/mpfr/add.c index 6aaf88ad7..f35f72b18 100644 --- a/mpfr/add.c +++ b/mpfr/add.c @@ -1,453 +1,131 @@ /* mpfr_add -- add two floating-point numbers -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999-2001 Free Software Foundation. +Contributed by the Spaces project, INRIA Lorraine. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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 */ - -extern void mpfr_sub1 _PROTO((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, - mp_rnd_t, int)); -void mpfr_add1 _PROTO((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t, int)); - -#define ONE ((mp_limb_t) 1) - -/* signs of b and c are supposed equal, - diff_exp is the difference between the exponents of b and c, - which is supposed >= 0 */ - -void -#if __STDC__ -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; - mp_rnd_t rnd_mode; - int diff_exp; -#endif +int +mpfr_add (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mp_rnd_t rnd_mode) { - mp_limb_t *ap, *bp, *cp, cc, c2, c3=0; unsigned int an,bn,cn; int sh,dif,k; - TMP_DECL(marker); - - TMP_MARK(marker); - ap = MPFR_MANT(a); - bp = MPFR_MANT(b); - cp = MPFR_MANT(c); - if (ap == bp) { - 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) + if (MPFR_IS_NAN(b) || MPFR_IS_NAN(c)) { - cp = (mp_ptr) TMP_ALLOC (MPFR_ABSSIZE(c) * BYTES_PER_MP_LIMB); - MPN_COPY(cp, ap, MPFR_ABSSIZE(c)); - } - - 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); - - 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 = 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>=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)) { - - MPN_COPY(ap+(an-bn), bp, bn); - /* fill low significant limbs with zero */ - - for (bp=ap;bn<an;bn++) *bp++=0; - - /* now take c into account */ - if (rnd_mode==GMP_RNDN) { - - /* to nearest */ - /* 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 add - one to the lsb of a if c>1/2, or c=1/2 and lsb(a)=1 (round to - even) */ - - if (MPFR_NOTZERO(c)) { - - /* c is not zero */ - /* check whether mant(c)=1/2 or not */ - - cc = *cp - (ONE<<(BITS_PER_MP_LIMB-1)); - if (cc==0) { - bp = cp+(MPFR_PREC(c)-1)/BITS_PER_MP_LIMB; - while (cp<bp && cc==0) cc = *++cp; - } - - if (cc || (ap[an-1] & (ONE<<sh))) goto add_one_ulp; - /* mant(c) != 1/2 or mant(c) = 1/2: add 1 iff lsb(a)=1 */ - } - } - } - else if ((MPFR_ISNONNEG(b) && rnd_mode==GMP_RNDU) || - (MPFR_ISNEG(b) && rnd_mode==GMP_RNDD)) { - - /* round up */ - if (MPFR_NOTZERO(c)) goto add_one_ulp; - } - /* in the other cases (round to zero, or up/down with sign -/+), - nothing to do */ - } - 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); - { /* 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 */ - } - else cc=0; - - 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)); - } - 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); - } - } - 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; - } + MPFR_SET_NAN(a); + MPFR_RET_NAN; } - } - else { - /* 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)/BITS_PER_MP_LIMB + 1; /* only the highest k limbs from c - have to be considered */ - 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 */ -#ifdef DEBUG - printf("MPFR_PREC(c)=%d\n", MPFR_PREC(c)); -#endif - 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, dif); - else if (dif<0) { - ap[k] = mpn_lshift(ap, cp+(cn-k), k, -dif); - - /* put the non-significant bits in low limb for further rounding */ + MPFR_CLEAR_NAN(a); - if (cn >= k+1) - ap[0] += cp[cn-k-1]>>(BITS_PER_MP_LIMB+dif); - } - else MPN_COPY(ap, cp+(cn-k), k); - overlap=1; + if (MPFR_IS_INF(b)) + { + if (!MPFR_IS_INF(c) || MPFR_SIGN(b) == MPFR_SIGN(c)) + { + MPFR_SET_INF(a); + MPFR_SET_SAME_SIGN(a, b); + MPFR_RET(0); /* exact */ + } + else + { + MPFR_SET_NAN(a); + MPFR_RET_NAN; + } } - else { - - /* c is not truncated, but we have to fill low limbs with 0 */ - - 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); - if (overlap) { - cc=mpn_rshift(ap+(an-k-cn), cp, cn, overlap); - if (an-k-cn>0) ap[an-k-cn-1]=cc; + else + if (MPFR_IS_INF(c)) + { + MPFR_SET_INF(a); + MPFR_SET_SAME_SIGN(a, c); + MPFR_RET(0); /* exact */ } - else MPN_COPY(ap+(an-k-cn), cp, cn); - overlap=0; - } - - /* here overlap=1 iff ulp(c)<ulp(a) */ - /* then put high limbs to zero */ - /* now add 'an' upper limbs of b in place */ - - if (MPFR_PREC(b)<=MPFR_PREC(a)) { - overlap += 2; - cc = mpn_add_n(ap+(an-bn), ap+(an-bn), bp, bn); - } - else - /* 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) && (MPFR_PREC(a)%BITS_PER_MP_LIMB==0); - mpn_rshift(ap, ap, an, 1); - ap[an-1] += ONE<<(BITS_PER_MP_LIMB-1); - MPFR_EXP(a)++; - } - - /* remains to do the rounding */ - -#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) 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 */ + MPFR_ASSERTN(MPFR_IS_FP(b) && MPFR_IS_FP(c)); - cc = *ap & ((ONE<<sh)-1); - *ap &= ~cc; /* truncate last bits */ - 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--; - cout += mpn_add_1(&cc, bp+(--k), 1,(cp[kc+1]<<(BITS_PER_MP_LIMB-dif)) - +(cp[kc]>>dif)); - 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; - } - - /* else round c: go through */ - - case 3: /* only c to round */ - bp=cp; k=cn-k; bn=cn; - goto to_nearest; - - case 0: /* only b to round */ - k=bn-an; dif=0; - goto to_nearest; - - /* 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 < 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 = (rnd_mode==GMP_RNDN) ? ONE<<(sh-1) : 0; - } - 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) { - /* special case of rouding c shifted to the right */ - 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 || (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) { - ap[an-1] = (mp_limb_t)1 << (BITS_PER_MP_LIMB-1); - MPFR_EXP(a)++; + if (MPFR_IS_ZERO(b)) + { + if (MPFR_IS_ZERO(c)) + { + if (MPFR_SIGN(a) != + (rnd_mode != GMP_RNDD ? + ((MPFR_SIGN(b) < 0 && MPFR_SIGN(c) < 0) ? -1 : 1) : + ((MPFR_SIGN(b) > 0 && MPFR_SIGN(c) > 0) ? 1 : -1))) + { + MPFR_CHANGE_SIGN(a); + } + MPFR_CLEAR_INF(a); + MPFR_SET_ZERO(a); + MPFR_RET(0); /* 0 + 0 is exact */ + } + return mpfr_set(a, c, rnd_mode); } - end_of_add: - TMP_FREE(marker); - return; -} - -void -#if __STDC__ -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; - mp_rnd_t rnd_mode; -#endif -{ - int diff_exp; - - 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; + if (MPFR_IS_ZERO(c)) + { + return mpfr_set(a, b, rnd_mode); } - 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 (!MPFR_NOTZERO(b)) { mpfr_set(a, c, rnd_mode); return; } - if (!MPFR_NOTZERO(c)) { mpfr_set(a, b, rnd_mode); return; } - - 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); + if (MPFR_SIGN(b) != MPFR_SIGN(c)) + { /* signs differ, it's a subtraction */ + if (MPFR_EXP(b) < MPFR_EXP(c)) + { + return mpfr_sub1(a, c, b, rnd_mode, + (mp_exp_unsigned_t) MPFR_EXP(c) - MPFR_EXP(b)); + } + else if (MPFR_EXP(b) > MPFR_EXP(c)) + { + return mpfr_sub1(a, b, c, rnd_mode, + (mp_exp_unsigned_t) MPFR_EXP(b) - MPFR_EXP(c)); + } + else + { /* MPFR_EXP(b) == MPFR_EXP(c) */ + int d = mpfr_cmp_abs(b,c); + if (d == 0) + { + if (rnd_mode == GMP_RNDD) + MPFR_SET_NEG(a); + else + MPFR_SET_POS(a); + MPFR_SET_ZERO(a); + MPFR_RET(0); + } + else if (d > 0) + return mpfr_sub1(a, b, c, rnd_mode, 0); + else + return mpfr_sub1(a, c, b, rnd_mode, 0); + } } - 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) 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); + else + { /* signs are equal, it's an addition */ + if (MPFR_EXP(b) < MPFR_EXP(c)) + { + return mpfr_add1(a, c, b, rnd_mode, + (mp_exp_unsigned_t) MPFR_EXP(c) - MPFR_EXP(b)); + } + else + { + return mpfr_add1(a, b, c, rnd_mode, + (mp_exp_unsigned_t) MPFR_EXP(b) - MPFR_EXP(c)); + } } - } - else /* signs are equal, it's an addition */ - if (diff_exp<0) mpfr_add1(a, c, b, rnd_mode, -diff_exp); - else mpfr_add1(a, b, c, rnd_mode, diff_exp); } - diff --git a/mpfr/add1.c b/mpfr/add1.c new file mode 100644 index 000000000..2c2cd39f0 --- /dev/null +++ b/mpfr/add1.c @@ -0,0 +1,548 @@ +/* mpfr_add1 -- internal function to perform a "real" addition + +Copyright (C) 1999-2001 Free Software Foundation. +Contributed by the Spaces project, INRIA Lorraine. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +/* signs of b and c are supposed equal, + diff_exp is the difference between the exponents of b and c, + which is supposed >= 0 */ + +int +mpfr_add1 (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, + mp_rnd_t rnd_mode, mp_exp_unsigned_t diff_exp) +{ + mp_limb_t *ap, *bp, *cp; + mp_prec_t aq, bq, cq, aq2; + mp_size_t an, bn, cn; + mp_exp_t difw; + int sh, rb, fb, inex; + TMP_DECL(marker); + + MPFR_ASSERTN(MPFR_IS_FP(b) && MPFR_NOTZERO(b)); + MPFR_ASSERTN(MPFR_IS_FP(c) && MPFR_NOTZERO(c)); + + TMP_MARK(marker); + ap = MPFR_MANT(a); + bp = MPFR_MANT(b); + cp = MPFR_MANT(c); + + if (ap == bp) + { + 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 (MPFR_ABSSIZE(c) * BYTES_PER_MP_LIMB); + MPN_COPY(cp, ap, MPFR_ABSSIZE(c)); + } + + aq = MPFR_PREC(a); + bq = MPFR_PREC(b); + cq = MPFR_PREC(c); + + an = (aq-1)/BITS_PER_MP_LIMB + 1; /* number of significant limbs of a */ + aq2 = an * BITS_PER_MP_LIMB; + sh = aq2 - aq; /* non-significant bits in low limb */ + bn = (bq-1)/BITS_PER_MP_LIMB + 1; /* number of significant limbs of b */ + cn = (cq-1)/BITS_PER_MP_LIMB + 1; /* number of significant limbs of c */ + + MPFR_EXP(a) = MPFR_EXP(b); + MPFR_SET_SAME_SIGN(a, b); + + /* + * 1. Compute the significant part A', the non-significant bits of A + * are taken into account. + * + * 2. Perform the rounding. At each iteration, we remember: + * _ r = rounding bit + * _ f = following bits (same value) + * where the result has the form: [number A]rfff...fff + a remaining + * value in the interval [0,2) ulp. We consider the most significant + * bits of the remaining value to update the result; a possible carry + * is immediately taken into account and A is updated accordingly. As + * soon as the bits f don't have the same value, A can be rounded. + * Variables: + * _ rb = rounding bit (0 or 1). + * _ fb = following bits (0 or 1), then sticky bit. + * If fb == 0, the only thing that can change is the sticky bit. + */ + + rb = fb = -1; /* means: not initialized */ + + if (aq2 <= diff_exp) + { /* c does not overlap with a' */ + if (an > bn) + { /* a has more limbs than b */ + /* copy b to the most significant limbs of a */ + MPN_COPY(ap + (an - bn), bp, bn); + /* zero the least significant limbs of a */ + MPN_ZERO(ap, an - bn); + } + else /* an <= bn */ + { + /* copy the most significant limbs of b to a */ + MPN_COPY(ap, bp + (bn - an), an); + } + } + else /* aq2 > diff_exp */ + { /* c overlaps with a' */ + mp_limb_t *a2p; + mp_limb_t cc; + mp_prec_t dif; + mp_size_t difn, k; + int shift; + + /* copy c (shifted) into a */ + + dif = aq2 - diff_exp; + /* dif is the number of bits of c which overlap with a' */ + + difn = (dif-1)/BITS_PER_MP_LIMB + 1; + /* only the highest difn limbs from c have to be considered */ + if (difn > cn) + { + /* c doesn't have enough limbs; take into account the virtual + zero limbs now by zeroing the least significant limbs of a' */ + MPFR_ASSERTN(difn - cn <= an); + MPN_ZERO(ap, difn - cn); + difn = cn; + } + + k = diff_exp / BITS_PER_MP_LIMB; + + /* zero the most significant k limbs of a */ + a2p = ap + (an - k); + MPN_ZERO(a2p, k); + + shift = diff_exp % BITS_PER_MP_LIMB; + + if (shift) + { + MPFR_ASSERTN(a2p - difn >= ap); + cc = mpn_rshift(a2p - difn, cp + (cn - difn), difn, shift); + if (a2p - difn > ap) + *(a2p - difn - 1) = cc; + } + else + MPN_COPY(a2p - difn, cp + (cn - difn), difn); + + /* add b to a */ + + cc = an > bn + ? mpn_add_n(ap + (an - bn), ap + (an - bn), bp, bn) + : mpn_add_n(ap, ap, bp + (bn - an), an); + + if (cc) /* carry */ + { + mp_exp_t exp = MPFR_EXP(a); + if (exp == __mpfr_emax) + { + inex = mpfr_set_overflow(a, rnd_mode, MPFR_SIGN(a)); + goto end_of_add; + } + MPFR_EXP(a)++; + rb = (ap[0] >> sh) & 1; /* LSB(a) --> rounding bit after the shift */ + if (sh) + { + mp_limb_t mask, bb; + + mask = (MP_LIMB_T_ONE << sh) - 1; + bb = ap[0] & mask; + ap[0] &= (~mask) << 1; + if (bb == 0) + fb = 0; + else if (bb == mask) + fb = 1; + } + mpn_rshift(ap, ap, an, 1); + ap[an-1] += MP_LIMB_T_HIGHBIT; + if (sh && fb < 0) + goto rounding; + } /* cc */ + } /* aq2 > diff_exp */ + + /* non-significant bits of a */ + if (rb < 0 && sh) + { + mp_limb_t mask, bb; + + mask = (MP_LIMB_T_ONE << sh) - 1; + bb = ap[0] & mask; + ap[0] &= ~mask; + rb = bb >> (sh - 1); + if (sh > 1) + { + mask >>= 1; + bb &= mask; + if (bb == 0) + fb = 0; + else if (bb == mask) + fb = 1; + else + goto rounding; + } + } + + /* determine rounding and sticky bits (and possible carry) */ + + difw = an - diff_exp / BITS_PER_MP_LIMB; + /* difw is the number of limbs from b (regarded as having an infinite + precision) that have already been combined with c; -n if the next + n limbs from b won't be combined with c. */ + + if (bn > an) + { /* there are still limbs from b that haven't been taken into account */ + mp_size_t bk; + + if (fb == 0 && difw <= 0) + { + fb = 1; /* c hasn't been taken into account ==> sticky bit != 0 */ + goto rounding; + } + + bk = bn - an; /* index of lowest considered limb from b, > 0 */ + while (difw < 0) + { /* ulp(next limb from b) > msb(c) */ + mp_limb_t bb; + + bb = bp[--bk]; + + MPFR_ASSERTD(fb != 0); + if (fb > 0) + { + if (bb != MP_LIMB_T_MAX) + { + fb = 1; /* c hasn't been taken into account + ==> sticky bit != 0 */ + goto rounding; + } + } + else /* fb not initialized yet */ + { + if (rb < 0) /* rb not initialized yet */ + { + rb = bb >> (BITS_PER_MP_LIMB - 1); + bb |= MP_LIMB_T_HIGHBIT; + } + fb = 1; + if (bb != MP_LIMB_T_MAX) + goto rounding; + } + + if (bk == 0) + { /* b has entirely been read */ + fb = 1; /* c hasn't been taken into account + ==> sticky bit != 0 */ + goto rounding; + } + + difw++; + } /* while */ + MPFR_ASSERTN(bk > 0 && difw >= 0); + + if (difw <= cn) + { + mp_size_t ck; + mp_limb_t cprev; + int difs; + + ck = cn - difw; + difs = diff_exp % BITS_PER_MP_LIMB; + + if (difs == 0 && ck == 0) + goto c_read; + + cprev = ck == cn ? 0 : cp[ck]; + + if (fb < 0) + { + mp_limb_t bb, cc; + + if (difs) + { + cc = cprev << (BITS_PER_MP_LIMB - difs); + if (--ck >= 0) + { + cprev = cp[ck]; + cc += cprev >> difs; + } + } + else + cc = cp[--ck]; + + bb = bp[--bk] + cc; + + if (bb < cc /* carry */ + && (rb < 0 || (rb ^= 1) == 0) + && mpn_add_1(ap, ap, an, MP_LIMB_T_ONE << sh)) + { + mp_exp_t exp = MPFR_EXP(a); + if (exp == __mpfr_emax) + { + inex = mpfr_set_overflow(a, rnd_mode, MPFR_SIGN(a)); + goto end_of_add; + } + MPFR_EXP(a)++; + ap[an-1] = MP_LIMB_T_HIGHBIT; + rb = 0; + } + + if (rb < 0) /* rb not initialized yet */ + { + rb = bb >> (BITS_PER_MP_LIMB - 1); + bb <<= 1; + bb |= bb >> (BITS_PER_MP_LIMB - 1); + } + + fb = bb != 0; + if (fb && bb != MP_LIMB_T_MAX) + goto rounding; + } /* fb < 0 */ + + while (bk > 0) + { + mp_limb_t bb, cc; + + if (difs) + { + if (ck < 0) + goto c_read; + cc = cprev << (BITS_PER_MP_LIMB - difs); + if (--ck >= 0) + { + cprev = cp[ck]; + cc += cprev >> difs; + } + } + else + { + if (ck == 0) + goto c_read; + cc = cp[--ck]; + } + + bb = bp[--bk] + cc; + if (bb < cc) /* carry */ + { + fb ^= 1; + if (fb) + goto rounding; + rb ^= 1; + if (rb == 0 && mpn_add_1(ap, ap, an, MP_LIMB_T_ONE << sh)) + { + mp_exp_t exp = MPFR_EXP(a); + if (exp == __mpfr_emax) + { + inex = mpfr_set_overflow(a, rnd_mode, MPFR_SIGN(a)); + goto end_of_add; + } + MPFR_EXP(a)++; + ap[an-1] = MP_LIMB_T_HIGHBIT; + } + } /* bb < cc */ + + if (!fb && bb != 0) + { + fb = 1; + goto rounding; + } + if (fb && bb != MP_LIMB_T_MAX) + goto rounding; + } /* while */ + + /* b has entirely been read */ + + if (fb || ck < 0) + goto rounding; + if (difs && cprev << (BITS_PER_MP_LIMB - difs)) + { + fb = 1; + goto rounding; + } + while (ck) + { + if (cp[--ck]) + { + fb = 1; + goto rounding; + } + } /* while */ + } /* difw <= cn */ + else + { /* c has entirely been read */ + c_read: + if (fb < 0) /* fb not initialized yet */ + { + mp_limb_t bb; + + MPFR_ASSERTN(bk > 0); + bb = bp[--bk]; + if (rb < 0) /* rb not initialized yet */ + { + rb = bb >> (BITS_PER_MP_LIMB - 1); + bb &= ~MP_LIMB_T_HIGHBIT; + } + fb = bb != 0; + } /* fb < 0 */ + if (fb) + goto rounding; + while (bk) + { + if (bp[--bk]) + { + fb = 1; + goto rounding; + } + } /* while */ + } /* difw > cn */ + } /* bn > an */ + else if (fb != 1) /* if fb == 1, the sticky bit is 1 (no possible carry) */ + { /* b has entirely been read */ + if (difw > cn) + { /* c has entirely been read */ + if (rb < 0) + rb = 0; + fb = 0; + } + else if (diff_exp > aq2) + { /* b is followed by at least a zero bit, then by c */ + if (rb < 0) + rb = 0; + fb = 1; + } + else + { + mp_size_t ck; + int difs; + + MPFR_ASSERTN(difw >= 0 && cn >= difw); + ck = cn - difw; + difs = diff_exp % BITS_PER_MP_LIMB; + + if (difs == 0 && ck == 0) + { /* c has entirely been read */ + if (rb < 0) + rb = 0; + fb = 0; + } + else + { + mp_limb_t cc; + + cc = difs ? (/*MPFR_ASSERTN(ck < cn),*/ + cp[ck] << (BITS_PER_MP_LIMB - difs)) : cp[--ck]; + if (rb < 0) + { + rb = cc >> (BITS_PER_MP_LIMB - 1); + cc &= ~MP_LIMB_T_HIGHBIT; + } + while (cc == 0) + { + if (ck == 0) + { + fb = 0; + goto rounding; + } + cc = cp[--ck]; + } /* while */ + fb = 1; + } + } + } /* fb != 1 */ + + rounding: + switch (rnd_mode) + { + case GMP_RNDN: + if (fb == 0) + { + if (rb == 0) + { + inex = 0; + goto end_of_add; + } + /* round to even */ + if (ap[0] & (MP_LIMB_T_ONE << sh)) + goto rndn_away; + else + goto rndn_zero; + } + if (rb == 0) + { + rndn_zero: + inex = MPFR_ISNEG(a) ? 1 : -1; + goto end_of_add; + } + else + { + rndn_away: + inex = MPFR_ISNONNEG(a) ? 1 : -1; + goto add_one_ulp; + } + + case GMP_RNDZ: + inex = rb || fb ? (MPFR_ISNEG(a) ? 1 : -1) : 0; + goto end_of_add; + + case GMP_RNDU: + inex = rb || fb; + if (inex && MPFR_ISNONNEG(a)) + goto add_one_ulp; + else + goto end_of_add; + + case GMP_RNDD: + inex = - (rb || fb); + if (inex && MPFR_ISNEG(a)) + goto add_one_ulp; + else + goto end_of_add; + + default: + MPFR_ASSERTN(0); + inex = 0; + goto end_of_add; + } + + add_one_ulp: /* add one unit in last place to a */ + if (mpn_add_1(ap, ap, an, MP_LIMB_T_ONE << sh)) + { + mp_exp_t exp = MPFR_EXP(a); + if (exp == __mpfr_emax) + inex = mpfr_set_overflow(a, rnd_mode, MPFR_SIGN(a)); + else + { + MPFR_EXP(a)++; + ap[an-1] = MP_LIMB_T_HIGHBIT; + } + } + + end_of_add: + TMP_FREE(marker); + return inex; +} diff --git a/mpfr/add_ui.c b/mpfr/add_ui.c index 43c08e316..eb1dfdcbf 100644 --- a/mpfr/add_ui.c +++ b/mpfr/add_ui.c @@ -1,20 +1,20 @@ /* mpfr_add_ui -- add a floating-point number with a machine integer -Copyright (C) 2000 Free Software Foundation. +Copyright (C) 2000-2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -26,29 +26,32 @@ MA 02111-1307, USA. */ #include "mpfr.h" #include "mpfr-impl.h" -void -#if __STDC__ +int 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); - } + + if (u) /* if u=0, do nothing */ + { + mpfr_t uu; + mp_limb_t up[1]; + unsigned long cnt; + int inex_add, inex_cr; + + 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; + + /* Optimization note: Exponent operations may be removed + if mpfr_add works even when uu is out-of-range. */ + mpfr_save_emin_emax(); + inex_add = mpfr_add(y, x, uu, rnd_mode); + mpfr_restore_emin_emax(); /* flags are restored too */ + inex_cr = mpfr_check_range(y, rnd_mode); + if (inex_cr) + return inex_cr; /* underflow or overflow */ + MPFR_RET(inex_add); + } else - mpfr_set (y, x, rnd_mode); + return mpfr_set (y, x, rnd_mode); } diff --git a/mpfr/add_ulp.c b/mpfr/add_ulp.c index d94fd73b6..a0c0e58f0 100644 --- a/mpfr/add_ulp.c +++ b/mpfr/add_ulp.c @@ -1,20 +1,20 @@ /* mpfr_add_one_ulp, mpfr_sub_one_ulp -- add/subtract one unit in last place -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -26,23 +26,21 @@ MA 02111-1307, USA. */ /* sets x to x+sign(x)*2^(MPFR_EXP(x)-MPFR_PREC(x)) */ void -#if __STDC__ -mpfr_add_one_ulp(mpfr_ptr x) -#else -mpfr_add_one_ulp(x) - mpfr_ptr x; -#endif +mpfr_add_one_ulp (mpfr_ptr x) { - int xn, sh; mp_limb_t *xp; + int xn, sh; + mp_limb_t *xp; - 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); + 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)) { - MPFR_EXP(x)++; - mpn_rshift(xp, xp, xn, 1); - xp[xn-1] += (mp_limb_t)1<<(BITS_PER_MP_LIMB-1); + if (mpn_add_1 (xp, xp, xn, MP_LIMB_T_ONE << sh)) /* got 1.0000... */ + { + MPFR_EXP(x)++; + xp[xn-1] = MP_LIMB_T_HIGHBIT; } return; } @@ -51,18 +49,21 @@ mpfr_add_one_ulp(x) void mpfr_sub_one_ulp(mpfr_ptr x) { - int xn, sh; mp_limb_t *xp; + int xn, sh; + mp_limb_t *xp; + + if (MPFR_IS_INF(x)) + return; - 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); + 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) { + mpn_sub_1 (xp, xp, xn, MP_LIMB_T_ONE << sh); + if (xp[xn-1] >> (BITS_PER_MP_LIMB - 1) == 0) { /* was an exact power of two: not normalized any more */ MPFR_EXP(x)--; - mpn_lshift(xp, xp, xn, 1); - *xp |= ((mp_limb_t)1 << sh); + mpn_lshift (xp, xp, xn, 1); + *xp |= MP_LIMB_T_ONE << sh; } return; } diff --git a/mpfr/agm.c b/mpfr/agm.c index 39d2782c6..b87ff9de3 100644 --- a/mpfr/agm.c +++ b/mpfr/agm.c @@ -5,21 +5,22 @@ Copyright (C) 1999, 2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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" @@ -61,22 +62,18 @@ _mpfr_ceil_exp2 (double d) /* now exp = ceil(d) */ x.d = 1.0; if (exp < -1022) exp = -1022; + else if (exp > 1024) { + fprintf (stderr, "Overflow in _mpfr_ceil_exp2\n"); + exit (1); + } x.s.exp = 1023 + exp; return x.d; } void -#ifdef __STDC__ mpfr_agm (mpfr_ptr r, mpfr_srcptr op2, mpfr_srcptr op1, mp_rnd_t rnd_mode) -#else -mpfr_agm (r, op2, op1, rnd_mode) - mpfr_ptr r; - mpfr_srcptr op2; - mpfr_srcptr op1; - mp_rnd_t rnd_mode; -#endif { - int s, go_on; + int s, go_on, compare; mp_prec_t p, q; double uo, vo; mp_limb_t *up, *vp, *tmpp, *tmpup, *tmpvp, *ap, *bp; @@ -84,25 +81,36 @@ mpfr_agm (r, op2, op1, rnd_mode) TMP_DECL(marker1); /* If a or b is NaN, the result is NaN */ - if (MPFR_IS_NAN(op1) || MPFR_IS_NAN(op2)) - { MPFR_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; } + { + MPFR_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_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 ((MPFR_NOTZERO(op1) && MPFR_NOTZERO(op2)) == 0) - { MPFR_SET_ZERO(r); - return; + { + MPFR_SET_ZERO(r); + return; } /* precision of the following calculus */ @@ -116,7 +124,6 @@ mpfr_agm (r, op2, op1, rnd_mode) s=(p-1)/BITS_PER_MP_LIMB+1; MPFR_INIT(ap, a, p, s); MPFR_INIT(bp, b, p, s); - { TMP_DECL(marker2); TMP_MARK(marker2); @@ -128,13 +135,22 @@ mpfr_agm (r, op2, op1, rnd_mode) - /* b and a will be the 2 operands but I want b>= a */ - if (mpfr_cmp(op1,op2) > 0) { - mpfr_set(b,op1,GMP_RNDN); mpfr_set(a,op2,GMP_RNDN); - } - else { - mpfr_set(b,op2,GMP_RNDN); mpfr_set(a,op1,GMP_RNDN); - } + /* b and a are the 2 operands but we want b >= a */ + if ((compare = mpfr_cmp (op1,op2)) > 0) + { + mpfr_set (b,op1,GMP_RNDN); + mpfr_set (a,op2,GMP_RNDN); + } + else if (compare == 0) + { + mpfr_set (r, op1, rnd_mode); + return; + } + else + { + mpfr_set (b,op2,GMP_RNDN); + mpfr_set (a,op1,GMP_RNDN); + } vo=mpfr_get_d(b); uo=mpfr_get_d(a); @@ -167,17 +183,12 @@ mpfr_agm (r, op2, op1, rnd_mode) mpfr_div_2exp(tmpv,tmp,1,GMP_RNDN); mpfr_set(u,tmpu,GMP_RNDN); mpfr_set(v,tmpv,GMP_RNDN); - if (mpfr_cmp(v,u)>=0) - eq=mpfr_cmp2(v,u); + if (mpfr_cmp(v,u) >= 0) + eq = mpfr_cmp2(v,u); else - eq=mpfr_cmp2(u,v); + eq = mpfr_cmp2(u,v); } - /* printf("avant can_round %i bits faux\n v : ",err+3); - mpfr_print_raw(v); printf("\n u : "); - mpfr_print_raw(u);printf("\n");*/ - - /* Roundability of the result */ can_round=mpfr_can_round(v,p-err-3,GMP_RNDN,rnd_mode,q); @@ -204,8 +215,6 @@ mpfr_agm (r, op2, op1, rnd_mode) /* Setting of the result */ mpfr_set(r,v,rnd_mode); - - TMP_FREE(marker2); } /* Let's clean */ diff --git a/mpfr/asin.c b/mpfr/asin.c new file mode 100644 index 000000000..27d15af2e --- /dev/null +++ b/mpfr/asin.c @@ -0,0 +1,181 @@ +/* mpfr_asin -- arc-sinus of a floating-point number + +Copyright (C) 2001 Free Software Foundation. + +This file is part of the MPFR Library, and was contributed by Mathieu Dutour. + +The MPFR 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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_asin (mpfr_ptr asin, mpfr_srcptr x, mp_rnd_t rnd_mode) +{ + mpfr_t xp; + mpfr_t arcs; + + int signe, suplement; + + mpfr_t tmp; + int Prec; + int prec_asin; + int good = 0; + int realprec; + int estimated_delta; + int compared; + + /* Trivial cases */ + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(asin); + return 1; + } + + /* Set x_p=|x| */ + signe = MPFR_SIGN(x); + mpfr_init2 (xp, MPFR_PREC(x)); + mpfr_set (xp, x, rnd_mode); + if (signe == -1) + MPFR_CHANGE_SIGN(xp); + + compared = mpfr_cmp_ui (xp, 1); + + if (compared > 0) /* asin(x) = NaN for |x| > 1 */ + { + MPFR_SET_NAN(asin); + mpfr_clear(xp); + return 1; + } + + if (compared == 0) /* x = 1 or x = -1 */ + { + if (signe > 0) /* asin(+1) = Pi/2 */ + mpfr_const_pi (asin, rnd_mode); + else /* asin(-1) = -Pi/2 */ + { + if (rnd_mode == GMP_RNDU) + rnd_mode = GMP_RNDD; + else if (rnd_mode == GMP_RNDD) + rnd_mode = GMP_RNDU; + mpfr_const_pi (asin, rnd_mode); + } + MPFR_EXP(asin)--; + mpfr_clear(xp); + return 1; /* inexact */ + } + + if (!MPFR_NOTZERO(x)) /* x = 0 */ + { + mpfr_set_ui (asin, 0, GMP_RNDN); + mpfr_clear(xp); + return 0; /* exact result */ + } + + prec_asin = MPFR_PREC(asin); + mpfr_ui_sub (xp, 1, xp, GMP_RNDD); + + suplement = 2 - MPFR_EXP(xp); +#ifdef DEBUG + printf("suplement=%d\n", suplement); +#endif + realprec = prec_asin + 10; + + while (!good) + { + estimated_delta = 1 + suplement; + Prec = realprec+estimated_delta; + + /* Initialisation */ + mpfr_init2 (tmp, Prec); + mpfr_init2 (arcs, Prec); + +#ifdef DEBUG + printf("Prec=%d\n", Prec); + printf(" x="); + mpfr_out_str (stdout, 2, 0, x, GMP_RNDN); + printf ("\n"); +#endif + mpfr_mul (tmp, x, x, GMP_RNDN); +#ifdef DEBUG + printf(" x^2="); + mpfr_out_str (stdout, 2, 0, tmp, GMP_RNDN); + printf ("\n"); +#endif + mpfr_ui_sub (tmp, 1, tmp, GMP_RNDN); +#ifdef DEBUG + printf(" 1-x^2="); + mpfr_out_str (stdout, 2, 0, tmp, GMP_RNDN); + printf ("\n"); + printf("10: 1-x^2="); + mpfr_out_str (stdout, 10, 0, tmp, GMP_RNDN); + printf ("\n"); +#endif + mpfr_sqrt (tmp, tmp, GMP_RNDN); +#ifdef DEBUG + printf(" sqrt(1-x^2)="); + mpfr_out_str (stdout, 2, 0, tmp, GMP_RNDN); + printf ("\n"); + printf("10: sqrt(1-x^2)="); + mpfr_out_str (stdout, 10, 0, tmp, GMP_RNDN); + printf ("\n"); +#endif + mpfr_div (tmp, x, tmp, GMP_RNDN); +#ifdef DEBUG + printf("x/sqrt(1-x^2)="); + mpfr_out_str (stdout, 2, 0, tmp, GMP_RNDN); + printf ("\n"); +#endif + mpfr_atan (arcs, tmp, GMP_RNDN); +#ifdef DEBUG + printf("atan(x/..x^2)="); + mpfr_out_str (stdout, 2, 0, arcs, GMP_RNDN); + printf ("\n"); +#endif + if (mpfr_can_round (arcs, realprec, GMP_RNDN, rnd_mode, MPFR_PREC(asin))) + { + mpfr_set (asin, arcs, rnd_mode); +#ifdef DEBUG + printf("asin ="); + mpfr_out_str (stdout, 2, prec_asin, asin, GMP_RNDN); + printf ("\n"); +#endif + good = 1; + } + else + { + realprec += _mpfr_ceil_log2 ((double) realprec); +#ifdef DEBUG + printf("RETRY\n"); +#endif + } + mpfr_clear (tmp); + mpfr_clear (arcs); + } + + mpfr_clear (xp); + + return 1; /* inexact result */ +} + + + + + diff --git a/mpfr/asinh.c b/mpfr/asinh.c new file mode 100644 index 000000000..a4ab317af --- /dev/null +++ b/mpfr/asinh.c @@ -0,0 +1,136 @@ +/* mpfr_asinh -- Inverse Hyperbolic Sinus of Unsigned Integer Number + +Copyright (C) 2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + + /* The computation of asinh is done by + + asinh= ln(x+sqrt(x^2+1)) + */ +int +mpfr_asinh (mpfr_ptr y, mpfr_srcptr xt , mp_rnd_t rnd_mode) +{ + int inexact =0; + mpfr_t x; + int flag_neg=0; + + mp_prec_t Nx=MPFR_PREC(xt); /* Precision of input variable */ + mpfr_init2(x,Nx); + mpfr_set(x,xt,GMP_RNDN); + + if (MPFR_SIGN(x) < 0) + { + MPFR_CHANGE_SIGN(x); + flag_neg=1; + } + + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(y); + mpfr_clear(x); + return 1; + } + MPFR_CLEAR_NAN(y); + + + if (MPFR_IS_INF(x)) + { + MPFR_SET_INF(y); + MPFR_SET_SAME_SIGN(y,x); + if(flag_neg) + MPFR_CHANGE_SIGN(y); + mpfr_clear(x); + return 1; + } + + MPFR_CLEAR_INF(y); + + if(!MPFR_NOTZERO(x)) + { + MPFR_SET_ZERO(y); /* asinh(0) = 0 */ + MPFR_SET_SAME_SIGN(y,x); + if(flag_neg) + MPFR_CHANGE_SIGN(y); + mpfr_clear(x); + return 0; + } + + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t t, te,ti; + + /* Declaration of the size variable */ + mp_prec_t Nx = MPFR_PREC(x); /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ + + mp_prec_t Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt=Nt+4+_mpfr_ceil_log2(Nt); + + /* initialise of intermediary variable */ + mpfr_init(t); + mpfr_init(te); + mpfr_init(ti); + + /* First computation of cosh */ + do { + + /* reactualisation of the precision */ + mpfr_set_prec(t,Nt); + mpfr_set_prec(te,Nt); + mpfr_set_prec(ti,Nt); + + /* compute asinh */ + mpfr_mul(te,x,x,GMP_RNDD); /* (x^2) */ + mpfr_add_ui(ti,te,1,GMP_RNDD); /* (x^2+1) */ + mpfr_sqrt(t,ti,GMP_RNDN); /* sqrt(x^2+1) */ + mpfr_add(t,t,x,GMP_RNDN); /* sqrt(x^2+1)+x */ + mpfr_log(t,t,GMP_RNDN); /* ln(sqrt(x^2+1)+x)*/ + + /* estimation of the error see- algorithms.ps*/ + /*err=Nt-_mpfr_ceil_log2(1+pow(2,3-MPFR_EXP(t)));*/ + err=Nt-(MAX(3-MPFR_EXP(t),0)+1); + + /* actualisation of the precision */ + Nt += 10; + + } while ((err < 0) || (!mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny) || (MPFR_IS_ZERO(t)))); + + if(flag_neg) + MPFR_CHANGE_SIGN(t); + + inexact = mpfr_set(y,t,rnd_mode); + + mpfr_clear(t); + mpfr_clear(ti); + mpfr_clear(te); + } + mpfr_clear(x); + return inexact; +} diff --git a/mpfr/atan.c b/mpfr/atan.c new file mode 100644 index 000000000..1c26c46e8 --- /dev/null +++ b/mpfr/atan.c @@ -0,0 +1,261 @@ +/* mpfr_atan -- arc-tangent of a floating-point number + +Copyright (C) 2001 Free Software Foundation. + +This file is part of the MPFR Library, and was contributed by Mathieu Dutour. + +The MPFR 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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" + +#define CST 2.27 /* CST=1+ln(2.4)/ln(2) */ +#define CST2 1.45 /* CST2=1/ln(2) */ + +static int mpfr_atan_aux _PROTO((mpfr_ptr, mpz_srcptr, int, int)); + +#undef B +#define A +#define A1 1 +#define A2 2 +#define C +#define C1 3 +#define C2 2 +#define NO_FACTORIAL +#define GENERIC mpfr_atan_aux +#include "generic.c" +#undef C +#undef C1 +#undef C2 +#undef A +#undef A1 +#undef A2 +#undef NO_FACTORIAL +#undef GENERIC + +int +mpfr_atan (mpfr_ptr arctangent, mpfr_srcptr x, mp_rnd_t rnd_mode) +{ + mpfr_t Pisur2; + mpfr_t xp; + mpfr_t arctgt; + + int comparaison, signe, suplement; + + mpfr_t t_arctan; + int i; + mpz_t ukz; + mpfr_t ukf; + mpfr_t sk,Ak; + mpz_t square; + mpfr_t tmp_arctan; + mpfr_t tmp, tmp2; +#ifdef DEBUG + mpfr_t tst; +#endif + int twopoweri; + int Prec; + int prec_x; + int prec_arctan; + int good = 0; + int realprec; + int estimated_delta; + /* calculation of the floor */ + int exptol; + + int N0; + int logn; + + /* Trivial cases */ + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(arctangent); + return 1; + } + + if (MPFR_IS_INF(x)) + { + if (MPFR_SIGN(x) > 0) /* arctan(+inf) = Pi/2 */ + mpfr_const_pi (arctangent, rnd_mode); + else /* arctan(-inf) = -Pi/2 */ + { + if (rnd_mode == GMP_RNDU) + rnd_mode = GMP_RNDD; + else if (rnd_mode == GMP_RNDD) + rnd_mode = GMP_RNDU; + mpfr_const_pi (arctangent, rnd_mode); + } + MPFR_EXP(arctangent)--; + return 1; /* inexact */ + } + + if (!MPFR_NOTZERO(x)) + { + mpfr_set_ui(arctangent, 0, GMP_RNDN); + return 0; /* exact result */ + } + + signe = MPFR_SIGN(x); + prec_arctan = MPFR_PREC(arctangent); + + /* Set x_p=|x| */ + mpfr_init2(xp, MPFR_PREC(x)); + mpfr_set(xp, x, rnd_mode); + if (signe == -1) + MPFR_CHANGE_SIGN(xp); + + /* Other simple case arctang(-+1)=-+pi/4 */ + comparaison=mpfr_cmp_ui(xp, 1); + if (comparaison == 0) { + mpfr_init2(Pisur2, prec_arctan); + mpfr_const_pi(Pisur2, rnd_mode); + mpfr_div_2exp(arctangent, Pisur2, 2, rnd_mode); + if (signe == -1) + MPFR_CHANGE_SIGN(arctangent); + mpfr_clear(Pisur2); + mpfr_clear(xp); + return 0; /* Result correct */ + } + if (comparaison > 0) + suplement = 1; + else + suplement = 2-MPFR_EXP(xp); + + prec_x = _mpfr_ceil_log2 ((double) MPFR_PREC(x) / BITS_PER_MP_LIMB); + logn = _mpfr_ceil_log2 ((double) prec_x); + if (logn < 2) logn = 2; + realprec = prec_arctan + _mpfr_ceil_log2((double) prec_arctan) + 4; + mpz_init(ukz); + mpz_init(square); + + + while (!good){ + N0 = _mpfr_ceil_log2((double) realprec + suplement + CST); + estimated_delta = 1 + suplement + _mpfr_ceil_log2((double) (3*N0-2)); + Prec = realprec+estimated_delta; + + /* Initialisation */ + mpfr_init2(sk,Prec); + mpfr_init2(ukf, Prec); + mpfr_init2(t_arctan, Prec); + mpfr_init2(tmp_arctan, Prec); + mpfr_init2(tmp, Prec); + mpfr_init2(tmp2, Prec); + mpfr_init2(Ak, Prec); + mpfr_init2(arctgt, Prec); + +#ifdef DEBUG + /* Tests */ + mpfr_init2(tst, realprec); +#endif + + if (comparaison > 0) + { + mpfr_init2(Pisur2, Prec); + mpfr_const_pi(Pisur2, GMP_RNDD); + mpfr_div_2exp(Pisur2, Pisur2, 1, GMP_RNDD); + mpfr_ui_div(sk, 1, xp, GMP_RNDD); + } + else + mpfr_set(sk, xp, GMP_RNDN); + + /* Assignation */ + mpfr_set_ui(tmp_arctan, 0, GMP_RNDN); + twopoweri = 1; + for(i = 0; i <= N0; i++){ + mpfr_mul_2exp(tmp, sk, twopoweri, GMP_RNDD); + /* Calculation of trunc(tmp) --> mpz */ + mpfr_trunc(ukf, tmp); + exptol=mpz_set_fr(ukz, ukf); + if (exptol>0) + mpz_mul_2exp(ukz, ukz, exptol); + else + mpz_tdiv_q_2exp(ukz, ukz, (unsigned long int) (-exptol)); + + /* Calculation of arctan(Ak) */ + mpz_mul(square, ukz, ukz); + mpz_neg(square, square); + mpfr_atan_aux(t_arctan, square, 2*twopoweri, N0 - i); + mpfr_set_z(Ak, ukz, GMP_RNDD); + mpfr_div_2exp(Ak, Ak, twopoweri, GMP_RNDD); + mpfr_mul(t_arctan, t_arctan, Ak, GMP_RNDD); + + /* Addition and iteration */ + mpfr_add(tmp_arctan, tmp_arctan, t_arctan, GMP_RNDD); + if (i<N0) + { + mpfr_sub(tmp, sk, Ak, GMP_RNDD); + mpfr_mul(tmp2, sk, Ak, GMP_RNDU); + mpfr_add_ui(tmp2, tmp2, 1, GMP_RNDU); + mpfr_div(sk, tmp, tmp2, GMP_RNDD); + twopoweri <<= 1; + } + } + + if (comparaison > 0) + { + mpfr_sub(arctgt, Pisur2, tmp_arctan, GMP_RNDD); + if (signe == -1) + MPFR_CHANGE_SIGN(arctgt); + } + else + { + mpfr_set(arctgt, tmp_arctan, GMP_RNDD); + if (signe == -1) + MPFR_CHANGE_SIGN(arctgt); + } + +#ifdef DEBUG + mpfr_set(tst, arctgt, rnd_mode); +#endif + + if (mpfr_can_round(arctgt, realprec, GMP_RNDD, rnd_mode, MPFR_PREC(arctangent))) + { + mpfr_set(arctangent, arctgt, rnd_mode); + good = 1; + realprec += 1; + } + else + { + realprec += _mpfr_ceil_log2 ((double) realprec); + } + + mpfr_clear(sk); + mpfr_clear(ukf); + mpfr_clear(t_arctan); + mpfr_clear(tmp_arctan); + mpfr_clear(tmp); + mpfr_clear(tmp2); + mpfr_clear(Ak); + mpfr_clear(arctgt); + +#ifdef DEBUG + mpfr_clear(tst); +#endif + if (comparaison > 0) + mpfr_clear(Pisur2); + } + + mpfr_clear(xp); + mpz_clear(ukz); + mpz_clear(square); + + return 1; /* inexact result */ +} diff --git a/mpfr/atanh.c b/mpfr/atanh.c new file mode 100644 index 000000000..b59f72659 --- /dev/null +++ b/mpfr/atanh.c @@ -0,0 +1,142 @@ +/* mpfr_atanh -- Inverse Hyperbolic Tangente of Unsigned Integer Number + +Copyright (C) 2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + + /* The computation of acosh is done by + + atanh= 1/2*ln(x+1)-1/2*ln(1-x) + */ + +int +mpfr_atanh (mpfr_ptr y, mpfr_srcptr xt , mp_rnd_t rnd_mode) +{ + int inexact =0; + mpfr_t x; + int flag_neg=0; + + mp_prec_t Nx=MPFR_PREC(xt); /* Precision of input variable */ + mpfr_init2(x,Nx); + mpfr_set(x,xt,GMP_RNDN); + + if (MPFR_SIGN(x) < 0) + { + MPFR_CHANGE_SIGN(x); + flag_neg=1; + } + + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(y); + mpfr_clear(x); + return 1; + } + MPFR_CLEAR_NAN(y); + + + if (MPFR_IS_INF(x)) + { + MPFR_SET_INF(y); + MPFR_SET_SAME_SIGN(y,x); + if(flag_neg) + MPFR_CHANGE_SIGN(y); + mpfr_clear(x); + return 0; + } + + MPFR_CLEAR_INF(y); + + if(!MPFR_NOTZERO(x)) + { + MPFR_SET_ZERO(y); /* atanh(0) = 0 */ + MPFR_SET_SAME_SIGN(y,x); + if(flag_neg) + MPFR_CHANGE_SIGN(y); + mpfr_clear(x); + return 0; + } + + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t t, te,ti; + + /* Declaration of the size variable */ + mp_prec_t Nx = MPFR_PREC(x); /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ + + mp_prec_t Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt=Nt+4+_mpfr_ceil_log2(Nt); + + /* initialise of intermediary variable */ + mpfr_init(t); + mpfr_init(te); + mpfr_init(ti); + + /* First computation of cosh */ + do { + + /* reactualisation of the precision */ + mpfr_set_prec(t,Nt); + mpfr_set_prec(te,Nt); + mpfr_set_prec(ti,Nt); + + /* compute atanh */ + mpfr_ui_sub(te,1,x,GMP_RNDU); /* (1-xt)*/ + mpfr_add_ui(ti,x,1,GMP_RNDD); /* (xt+1)*/ + mpfr_div(te,ti,te,GMP_RNDN); /* (1+xt)/(1-xt)*/ + mpfr_log(te,te,GMP_RNDN); /* ln((1+xt)/(1-xt))*/ + mpfr_div_2exp(t,te,1,GMP_RNDN); /* (1/2)*ln((1+xt)/(1-xt))*/ + + /* estimation of the error see- algorithms.ps*/ + /* err=Nt-_mpfr_ceil_log2(1+5*pow(2,1-MPFR_EXP(t)));*/ + err=Nt-(MAX(4-MPFR_EXP(t),0)+1); + + /* actualisation of the precision */ + Nt += 10; + + } while ((err < 0) || (!mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny) || (MPFR_IS_ZERO(t)))); + + if(flag_neg) + MPFR_CHANGE_SIGN(t); + + inexact = mpfr_set(y,t,rnd_mode); + + mpfr_clear(t); + mpfr_clear(ti); + mpfr_clear(te); + } + mpfr_clear(x); + return inexact; +} + + + + + diff --git a/mpfr/ceil.c b/mpfr/ceil.c new file mode 100644 index 000000000..4ec951671 --- /dev/null +++ b/mpfr/ceil.c @@ -0,0 +1,2 @@ +#define MPFR_CEIL 1 +#include "trunc.c" diff --git a/mpfr/clear.c b/mpfr/clear.c index 0b1db32fd..635a02068 100644 --- a/mpfr/clear.c +++ b/mpfr/clear.c @@ -1,20 +1,20 @@ /* mpfr_clear -- free the memory space allocated for a floating-point number -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999-2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -26,12 +26,7 @@ MA 02111-1307, USA. */ #include "mpfr-impl.h" void -#if __STDC__ mpfr_clear (mpfr_ptr m) -#else -mpfr_clear (m) - mpfr_ptr m; -#endif { /* be careful to always free an entire number of limbs */ (*__gmp_free_func) (MPFR_MANT(m), MPFR_ABSSIZE(m) * BYTES_PER_MP_LIMB); diff --git a/mpfr/cmp.c b/mpfr/cmp.c index 5b7b73cf5..ec6fdd166 100644 --- a/mpfr/cmp.c +++ b/mpfr/cmp.c @@ -1,249 +1,94 @@ /* mpfr_cmp -- compare two floating-point numbers -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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" -/* returns 0 iff b = c - a positive value iff b > c - a negative value iff b < c - -More precisely, in case b and c are of same sign, the absolute value -of the result is one plus the absolute difference between the exponents -of b and c, i.e. one plus the number of bits shifts to align b and c -(this value is useful in mpfr_sub). - +/* returns 0 iff b = sign(s) * c + a positive value iff b > sign(s) * c + a negative value iff b < sign(s) * c */ -/* #define DEBUG */ - -/* compares b and sign(s)*c */ -int -#if __STDC__ -mpfr_cmp3 (mpfr_srcptr b, mpfr_srcptr c, long int s) -#else -mpfr_cmp3 (b, c, s) - mpfr_srcptr b; - mpfr_srcptr c; - long int s; -#endif +int +mpfr_cmp3 (mpfr_srcptr b, mpfr_srcptr c, int s) { - long int diff_exp; - unsigned long bn, cn; - mp_limb_t *bp, *cp; - - if (MPFR_IS_NAN(b) || MPFR_IS_NAN(c)) return 1; + mp_exp_t be, ce; + mp_size_t bn, cn; + mp_limb_t *bp, *cp; - 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); - } + MPFR_ASSERTN(!MPFR_IS_NAN(b)); + MPFR_ASSERTN(!MPFR_IS_NAN(c)); + s *= MPFR_SIGN(c); - 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); + if (MPFR_IS_INF(b)) + return (MPFR_IS_INF(c) && s * MPFR_SIGN(b) > 0) ? 0 : MPFR_SIGN(b); - s = s * MPFR_SIGN(b) * MPFR_SIGN(c); - if (s<0) return(MPFR_SIGN(b)); + if (MPFR_IS_INF(c)) + return -s; - /* now signs are equal */ - diff_exp = MPFR_EXP(b)-MPFR_EXP(c); - s = (MPFR_SIGN(b) > 0) ? 1 : -1; + /* b and c are real numbers */ - 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 */ + if (MPFR_IS_ZERO(b)) + return MPFR_IS_ZERO(c) ? 0 : -s; - 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); + if (MPFR_IS_ZERO(c)) + return MPFR_SIGN(b); - while (bn && cn) { - if (bp[--bn] != cp[--cn]) - return((bp[bn]>cp[cn]) ? s : -s); - } + if (s * MPFR_SIGN(b) < 0) + return MPFR_SIGN(b); - if (bn) { while (bn) if (bp[--bn]) return(s); } - else if (cn) while (cn) if (cp[--cn]) return(-s); + /* now signs are equal */ - return 0; -} + be = MPFR_EXP(b); + ce = MPFR_EXP(c); + if (be > ce) + return s; + if (be < ce) + return -s; -/* returns the number of cancelled bits when one subtracts abs(c) from abs(b). - Assumes b>=c, which implies MPFR_EXP(b)>=MPFR_EXP(c). - if b=c, returns prec(b). + /* both signs and exponents are equal */ - In other terms mpfr_cmp2 (b, c) returns EXP(b) - EXP(b-c). -*/ -int -#if __STDC__ -mpfr_cmp2 ( mpfr_srcptr b, mpfr_srcptr c ) -#else -mpfr_cmp2(b, c) - mpfr_srcptr b; - mpfr_srcptr c; -#endif -{ - long int d, bn, cn, k, z; - mp_limb_t *bp, *cp, t, u=0, cc=0; - -#ifdef DEBUG - printf("b="); mpfr_print_raw(b); putchar('\n'); - printf("c="); mpfr_print_raw(c); putchar('\n'); -#endif - 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 - printf("d=%u\n", d); - if (d<0) { printf("assumption MPFR_EXP(b)<MPFR_EXP(c) violated\n"); exit(1); } -#endif 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 < BITS_PER_MP_LIMB) - cc -= cp[cn] >> d; - } - else { /* d=0 */ - while (bn>=0 && cn>=0 && (cc=(bp[bn--]-cp[cn--]))==0) { - k+=BITS_PER_MP_LIMB; - } - - if (cc==0) { /* either bn<0 or cn<0 */ - while (bn>=0 && (cc=bp[bn--])==0) k+=BITS_PER_MP_LIMB; - } - /* now bn<0 or cc<>0 */ - 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; + bp = MPFR_MANT(b); + cp = MPFR_MANT(c); - 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) - /* We just need to compare the following limbs */ - /* until two of them differ. The result is either k or k+1. */ + for ( ; bn >= 0 && cn >= 0; bn--, cn--) { - /* First flush all the unmatched limbs of b ; they all have to - be 0 in order for the process to go on */ - while (bn >= 0) - { - if (cn < 0) { return k; } - t = bp[bn--]; - if (d < BITS_PER_MP_LIMB) - { - if (d) - { - u = cp[cn--] << (BITS_PER_MP_LIMB - d); - if (cn >= 0) u+=(cp[cn]>>d); - } - else u = cp[cn--]; - - if (t > u || (t == u && cn < 0)) return k; - if (t < u) return k+1; - } - else - 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 d < BITS_PER_MP_LIMB, only the last d bits of cp[cn] have to be - considered, otherwise all bits */ - if (d < BITS_PER_MP_LIMB) - if (cn>=0 && (cp[cn--] << (BITS_PER_MP_LIMB - d))) { return k+1; } - - while (cn >= 0) - if (cp[cn--]) return k+1; - return k; + if (bp[bn] > cp[cn]) + return s; + if (bp[bn] < cp[cn]) + return -s; } - /* cc = 1. Too bad. */ - 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 > BITS_PER_MP_LIMB) return k; - - while (bn >= 0) /* the next limb of b to be considered is b[bn] */ - { - /* 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--] << (BITS_PER_MP_LIMB - d); - if (cn >= 0) u += cp[cn] >> d; - } - else u = cp[cn--]; - - /* bp[bn--] > cp[cn--] : no borrow possible, k unchanged - bp[bn--] = cp[cn--] : need to consider next limbs - bp[bn--] < cp[cn--] : borrow - */ - if ((cc = bp[bn--]) != 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 += BITS_PER_MP_LIMB; - } + for ( ; bn >= 0; bn--) + if (bp[bn]) + return s; - /* 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; - - /* 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 += 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 */ + for ( ; cn >= 0; cn--) + if (cp[cn]) + return -s; + + return 0; } diff --git a/mpfr/cmp2.c b/mpfr/cmp2.c new file mode 100644 index 000000000..725cf5867 --- /dev/null +++ b/mpfr/cmp2.c @@ -0,0 +1,183 @@ +/* mpfr_cmp2 -- exponent shift when subtracting two numbers. + +Copyright (C) 1999-2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +/* returns the number of cancelled bits when one subtracts abs(c) from abs(b). + Assumes |b| >= |c|, which implies MPFR_EXP(b)>=MPFR_EXP(c). + if |b| = |c|, returns prec(b). + + Assumes neither of b or c is NaN or +/- infinity. + + In other terms mpfr_cmp2 (b, c) returns EXP(b) - EXP(b-c). +*/ +mp_prec_t +mpfr_cmp2 (mpfr_srcptr b, mpfr_srcptr c) +{ + mp_limb_t *bp, *cp, bb, cc = 0, lastc = 0, dif, high_dif = 0; + mp_size_t bn, cn; + mp_exp_unsigned_t diff_exp; + mp_prec_t res = 0; + + MPFR_ASSERTN(MPFR_IS_FP(b)); + MPFR_ASSERTN(MPFR_IS_FP(c)); + + if (MPFR_IS_ZERO(c)) + return 0; + + MPFR_ASSERTN(MPFR_NOTZERO(b)); + + bp = MPFR_MANT(b); + cp = MPFR_MANT(c); + + bn = (MPFR_PREC(b) - 1) / BITS_PER_MP_LIMB; + cn = (MPFR_PREC(c) - 1) / BITS_PER_MP_LIMB; + + MPFR_ASSERTN(MPFR_EXP(b) >= MPFR_EXP(c)); + diff_exp = (mp_exp_unsigned_t) MPFR_EXP(b) - MPFR_EXP(c); + + if (diff_exp == 0) /* otherwise the shifted most significant limb of c + cannot match bp[bn] */ + { + while (bn>=0 && cn>=0 && bp[bn] == cp[cn]) + { + bn--; + cn--; + res += BITS_PER_MP_LIMB; + } + + if (bn < 0) /* b = c */ + return MPFR_PREC(b); + + if (cn < 0) /* c discards exactly the upper part of b */ + { + unsigned int z; + + while (bn>=0 && bp[bn]==0) + { + bn--; + res += BITS_PER_MP_LIMB; + } + + if (bn < 0) /* b = c */ + return MPFR_PREC(b); + + count_leading_zeros(z, bp[bn]); /* bp[bn] <> 0 */ + return res + z; + } + } + + /* now we have removed the identical upper limbs of b and c + (can happen only when diff_exp = 0): bp[bn] > cc, bn>=0, cn>=0 */ + + if (diff_exp < BITS_PER_MP_LIMB) + { + cc = cp[cn] >> diff_exp; + /* warning: a shift by BITS_PER_MP_LIMB may give wrong results */ + if (diff_exp) + lastc = cp[cn] << (BITS_PER_MP_LIMB - diff_exp); + cn--; + } + else + diff_exp -= BITS_PER_MP_LIMB; + + dif = bp[bn--] - cc; /* necessarily dif >= 1 */ + + while ((cn >= 0 || lastc != 0) && (high_dif == 0) && (dif == 1)) + { /* dif=1 implies diff_exp = 0 or 1 */ + bb = (bn >= 0) ? bp[bn] : 0; + cc = lastc; + if (cn >= 0) + { + if (diff_exp == 0) + { + cc += cp[cn]; + } + else /* diff_exp = 1 */ + { + cc += cp[cn] >> 1; + lastc = cp[cn] << (BITS_PER_MP_LIMB - 1); + } + } + else + lastc = 0; + high_dif = 1 - mpn_sub_n (&dif, &bb, &cc, 1); + bn--; + cn--; + res += BITS_PER_MP_LIMB; + } + + /* (cn<0 and lastc=0) or (high_dif,dif)<>(0,1) */ + + if (high_dif != 0) /* necessarily high_dif = 1 */ + { + res--; + if (dif != 0) + return res; + } + else /* high_dif = 0 */ + { + unsigned int z; + + count_leading_zeros(z, dif); /* dif > 1 here */ + res += z; + if (dif != (MP_LIMB_T_ONE << (BITS_PER_MP_LIMB - z - 1))) + return res; /* dif is not a power of two */ + } + + /* now result is res + (low(b) < low(c)) */ + while (bn >= 0 && (cn >= 0 || lastc != 0)) + { + if (diff_exp >= BITS_PER_MP_LIMB) + diff_exp -= BITS_PER_MP_LIMB; + else + { + cc = lastc; + if (cn >= 0) + { + cc += cp[cn] >> diff_exp; + if (diff_exp != 0) + lastc = cp[cn] << (BITS_PER_MP_LIMB - diff_exp); + } + else + lastc = 0; + cn--; + } + if (bp[bn] != cc) + return res + (bp[bn] < cc); + bn--; + } + + if (bn < 0) + { + if (lastc != 0) + return res + 1; + while (cn >= 0 && cp[cn] == 0) + cn--; + return res + (cn >= 0); + } + + return res; /* remainder from c is 0 */ +} diff --git a/mpfr/cmp_abs.c b/mpfr/cmp_abs.c new file mode 100644 index 000000000..cae56154e --- /dev/null +++ b/mpfr/cmp_abs.c @@ -0,0 +1,72 @@ +/* mpfr_cmp_abs -- compare the absolute values of two nonzero FP numbers + +Copyright (C) 1999, 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +/* returns sign(abs(b) - abs(c)) + b and c must be nonzero real numbers */ + +int +mpfr_cmp_abs (mpfr_srcptr b, mpfr_srcptr c) +{ + mp_exp_t be, ce; + mp_size_t bn, cn; + mp_limb_t *bp, *cp; + + MPFR_ASSERTN(MPFR_IS_FP(b) && MPFR_NOTZERO(b)); + MPFR_ASSERTN(MPFR_IS_FP(c) && MPFR_NOTZERO(c)); + + be = MPFR_EXP(b); + ce = MPFR_EXP(c); + if (be > ce) + return 1; + if (be < ce) + return -1; + + /* exponents are equal */ + + 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); + + for ( ; bn >= 0 && cn >= 0; bn--, cn--) + { + if (bp[bn] > cp[cn]) + return 1; + if (bp[bn] < cp[cn]) + return -1; + } + + for ( ; bn >= 0; bn--) + if (bp[bn]) + return 1; + + for ( ; cn >= 0; cn--) + if (cp[cn]) + return -1; + + return 0; +} diff --git a/mpfr/cmp_ui.c b/mpfr/cmp_ui.c index 364881970..421d2b43a 100644 --- a/mpfr/cmp_ui.c +++ b/mpfr/cmp_ui.c @@ -1,20 +1,20 @@ /* mpfr_cmp_ui -- compare a floating-point number with a machine integer -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -32,23 +32,17 @@ MA 02111-1307, USA. */ */ int -#if __STDC__ mpfr_cmp_ui_2exp (mpfr_srcptr b, unsigned long int i, int f ) -#else -mpfr_cmp_ui_2exp (b, i, f) - mpfr_srcptr b; - unsigned long int i; - int f; -#endif { int e, k, bn; mp_limb_t c, *bp; 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); + if (MPFR_IS_INF(b)) return (MPFR_SIGN(b) > 0) ? 1 : -1; + + /* now b is neither NaN nor +/-Infinity */ + if (!MPFR_NOTZERO(b)) return((i) ? -1 : 0); + else if (MPFR_SIGN(b) < 0) return -1; /* now b>0 */ else if (i==0) return 1; else { /* b>0, i>0 */ @@ -80,14 +74,7 @@ mpfr_cmp_ui_2exp (b, i, f) */ int -#if __STDC__ mpfr_cmp_si_2exp (mpfr_srcptr b, long int i, int f ) -#else -mpfr_cmp_si_2exp (b, i, f) - mpfr_srcptr b; - long int i; - int f; -#endif { int e, k, bn, si; mp_limb_t c, *bp; diff --git a/mpfr/copysign.c b/mpfr/copysign.c new file mode 100644 index 000000000..1dd88dc2f --- /dev/null +++ b/mpfr/copysign.c @@ -0,0 +1,76 @@ +/* mpfr_copysign -- Produce a value with the magnitude of x and sign of y + +Copyright (C) 2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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" + + /* The computation of z with magnitude of x and sign of y + + z = sign(y) * abs(x) + */ + +int +mpfr_copysign (mpfr_ptr z, mpfr_srcptr x ,mpfr_srcptr y , mp_rnd_t rnd_mode) +{ + + if (MPFR_IS_NAN(y)) + { + MPFR_SET_NAN(z); + return 1; + } + + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(z); + MPFR_SET_SAME_SIGN(z,y); + return 1; + } + + MPFR_CLEAR_NAN(z); + + if (MPFR_IS_INF(x)) { + + MPFR_SET_INF(z); + MPFR_SET_SAME_SIGN(z,y); + return 0; + } + + MPFR_CLEAR_INF(z); + + if (!MPFR_NOTZERO(x)) + { + MPFR_SET_ZERO(z); + MPFR_SET_SAME_SIGN(z,y); + return 0; + } + + /* GENERAL CASE*/ + { + int inexact=0; + inexact =mpfr_set(z,x,rnd_mode); + MPFR_SET_SAME_SIGN(z,y); + return inexact; + } + +} diff --git a/mpfr/cos.c b/mpfr/cos.c new file mode 100644 index 000000000..02461cedc --- /dev/null +++ b/mpfr/cos.c @@ -0,0 +1,137 @@ +/* mpfr_cos -- cosine of a floating-point number + +Copyright (C) 2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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" + +static int mpfr_cos2_aux _PROTO ((mpfr_ptr, mpfr_srcptr)); + +int +mpfr_cos (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode) +{ + int K, precy, m, k, l, inexact; + mpfr_t r, s; + + if (MPFR_IS_NAN(x) || MPFR_IS_INF(x)) + { + MPFR_SET_NAN(y); + return 1; + } + + if (!MPFR_NOTZERO(x)) + { + mpfr_set_ui (y, 1, GMP_RNDN); + return 0; + } + + precy = MPFR_PREC(y); + + K = _mpfr_isqrt(precy / 2); + if (MPFR_EXP(x) > 0) + K += MPFR_EXP(x); + /* we need at least K + log2(precy/K) extra bits */ + m = precy + 3 * K + 3; + + mpfr_init2 (r, m); + mpfr_init2 (s, m); + + do + { + mpfr_mul (r, x, x, GMP_RNDU); /* err <= 1 ulp */ + mpfr_div_2exp (r, r, 2 * K, GMP_RNDN); /* r = (x/2^K)^2, err <= 1 ulp */ + + /* s <- 1 - r/2! + ... + (-1)^l r^l/(2l)! */ + l = mpfr_cos2_aux (s, r); + + for (k = 0; k < K; k++) + { + mpfr_mul (s, s, s, GMP_RNDU); /* err <= 2*olderr */ + mpfr_mul_2exp (s, s, 1, GMP_RNDU); /* err <= 4*olderr */ + mpfr_sub_ui (s, s, 1, GMP_RNDN); + } + + /* absolute error on s is bounded by (2l+1/3)*2^(2K-m) */ + for (k = 2 * K, l = 2 * l + 1; l > 1; k++, l = (l + 1) >> 1); + /* now the error is bounded by 2^(k-m) = 2^(EXP(s)-err) */ + + l = mpfr_can_round (s, MPFR_EXP(s) + m - k, GMP_RNDN, rnd_mode, precy); + + if (l == 0) + { + m += BITS_PER_MP_LIMB; + mpfr_set_prec (r, m); + mpfr_set_prec (s, m); + } + } + while (l == 0); + + inexact = mpfr_set (y, s, rnd_mode); + + mpfr_clear (r); + mpfr_clear (s); + + return inexact; +} + +/* s <- 1 - r/2! + r^2/4! + ... + (-1)^l r^l/(2l)! + ... + Assumes |r| < 1. + Returns the index l0 of the last term (-1)^l r^l/(2l)!. + The absolute error on s is at most 2 * l0 * 2^(-m). +*/ +static int +mpfr_cos2_aux (mpfr_ptr s, mpfr_srcptr r) +{ + unsigned int l, b = 2; + int prec_t, m = MPFR_PREC(s); + mpfr_t t; + + MPFR_ASSERTN (MPFR_EXP(r) <= 0); + mpfr_init2 (t, m); + mpfr_set_ui (t, 1, GMP_RNDN); + mpfr_set_ui(s, 1, GMP_RNDN); + + for (l = 1; MPFR_EXP(t) >= -m; l++) + { + mpfr_mul (t, t, r, GMP_RNDU); /* err <= (3l-1) ulp */ + mpfr_div_ui (t, t, (2*l-1)*(2*l), GMP_RNDU); /* err <= 3l ulp */ + if (l % 2 == 0) + mpfr_add (s, s, t, GMP_RNDD); + else + mpfr_sub (s, s, t, GMP_RNDD); + MPFR_ASSERTN (MPFR_EXP(s) == 0); /* check 1/2 <= s < 1 */ + /* err(s) <= l * 2^(-m) */ + if (3 * l > (1 << b)) + b++; + /* now 3l <= 2^b, we want 3l*ulp(t) <= 2^(-m) + i.e. b+EXP(t)-PREC(t) <= -m */ + prec_t = m + MPFR_EXP(t) + b; + if (prec_t > 0) + mpfr_round (t, GMP_RNDN, prec_t); + } + + mpfr_clear (t); + + return l; +} + diff --git a/mpfr/cosh.c b/mpfr/cosh.c new file mode 100644 index 000000000..98b0ede6e --- /dev/null +++ b/mpfr/cosh.c @@ -0,0 +1,126 @@ +/* mpfr_cosh -- hyperbolic cosine + +Copyright (C) 2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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" + + /* The computation of cosh is done by + + cosh= 1/2[e^(x)+e^(-x)] + */ + +int +mpfr_cosh (mpfr_ptr y, mpfr_srcptr xt , mp_rnd_t rnd_mode) +{ + + /****** Declaration ******/ + mpfr_t x; + mp_prec_t Nxt = MPFR_PREC(xt); + int inexact =0; + + if (MPFR_IS_NAN(xt)) + { + MPFR_SET_NAN(y); + return 1; + } + MPFR_CLEAR_NAN(y); + + if (MPFR_IS_INF(xt)) + { + MPFR_SET_INF(y); + if (MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN(y); + return 0; + } + + MPFR_CLEAR_INF(y); + + if(!MPFR_NOTZERO(xt)) + return mpfr_set_ui(y,1,rnd_mode); /* cosh(0) = 1 */ + + mpfr_init2(x,Nxt); + mpfr_set(x,xt,GMP_RNDN); + + if(MPFR_SIGN(x)<0) + { + MPFR_CHANGE_SIGN(x); + } + + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t t, te,ti; + + /* Declaration of the size variable */ + mp_prec_t Nx = Nxt; /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ + + mp_prec_t Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt=Nt+3+_mpfr_ceil_log2(Nt); + + + /* initialise of intermediary variable */ + mpfr_init(t); + mpfr_init(te); + mpfr_init(ti); + + + /* First computation of cosh */ + do { + + /* reactualisation of the precision */ + + mpfr_set_prec(t,Nt); + mpfr_set_prec(te,Nt); + mpfr_set_prec(ti,Nt); + + /* compute cosh */ + mpfr_exp(te,x,GMP_RNDD); /* exp(x) */ + mpfr_ui_div(ti,1,te,GMP_RNDU); /* 1/exp(x) */ + mpfr_add(t,te,ti,GMP_RNDN); /* exp(x) + 1/exp(x)*/ + mpfr_div_2exp(t,t,1,GMP_RNDN); /* 1/2(exp(x) + 1/exp(x))*/ + + /* estimation of the error */ + err=Nt-3; + + /* actualisation of the precision */ + Nt += 10; + + } while ((err <0) || !mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny)); + + inexact = mpfr_set(y,t,rnd_mode); + + mpfr_clear(t); + mpfr_clear(ti); + mpfr_clear(te); + } + mpfr_clear(x); + return inexact; + +} diff --git a/mpfr/dim.c b/mpfr/dim.c new file mode 100644 index 000000000..4715ba95d --- /dev/null +++ b/mpfr/dim.c @@ -0,0 +1,55 @@ +/* mpfr_dim -- dim of x, y + +Copyright (C) 2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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" + + /* The computation of z=dim(x,y) + + x-y if x > y + +0 if x <= y + */ + +int +mpfr_dim (mpfr_ptr z, mpfr_srcptr x ,mpfr_srcptr y , mp_rnd_t rnd_mode) +{ + + if (MPFR_IS_NAN(x) || MPFR_IS_NAN(y) ) + { + MPFR_SET_NAN(z); + return 1; + } + MPFR_CLEAR_NAN(z); + + if(mpfr_cmp(x,y) > 0) + return mpfr_sub(z,x,y,rnd_mode); + else + { + MPFR_SET_ZERO(z); + if(MPFR_SIGN(z) < 0) + MPFR_CHANGE_SIGN(z); + return 0; + } +} + diff --git a/mpfr/div.c b/mpfr/div.c index bf5ffc371..9f9b2850a 100644 --- a/mpfr/div.c +++ b/mpfr/div.c @@ -1,20 +1,20 @@ /* mpfr_div -- divide two floating-point numbers -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -27,284 +27,424 @@ MA 02111-1307, USA. */ #include "mpfr.h" #include "mpfr-impl.h" -/* #define DEBUG */ - -void -#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 +int +mpfr_div (mpfr_ptr q, mpfr_srcptr u, mpfr_srcptr v, mp_rnd_t rnd_mode) { - mp_srcptr up, vp; - 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, t; - unsigned long cc = 0, rw, nw; - char can_round = 0; + mp_srcptr up, vp, bp; + mp_size_t usize, vsize; + + mp_ptr ap, qp, rp; + mp_size_t asize, bsize, qsize, rsize; + mp_exp_t qexp; + + mp_rnd_t rnd_mode1, rnd_mode2; + + mp_size_t err, k; + mp_limb_t near; + int inex, sh, can_round, can_round2, sign_quotient; + unsigned int cc = 0, rw; + TMP_DECL (marker); - if (MPFR_IS_NAN(u) || MPFR_IS_NAN(v)) { MPFR_SET_NAN(r); return; } - MPFR_CLEAR_NAN(r); + /************************************************************************** + * * + * This part of the code deals with special cases * + * * + **************************************************************************/ + + if (MPFR_IS_NAN(u) || MPFR_IS_NAN(v)) + { + MPFR_SET_NAN(q); MPFR_RET_NAN; + } + + MPFR_CLEAR_NAN(q); if (MPFR_IS_INF(u)) { if (MPFR_IS_INF(v)) - MPFR_SET_NAN(r); + { + MPFR_SET_NAN(q); MPFR_RET_NAN; + } else { - MPFR_SET_INF(r); - if (MPFR_SIGN(r) != MPFR_SIGN(u) * MPFR_SIGN(v)) - MPFR_CHANGE_SIGN(r); + MPFR_SET_INF(q); + if (MPFR_SIGN(q) != MPFR_SIGN(u) * MPFR_SIGN(v)) + MPFR_CHANGE_SIGN(q); + MPFR_RET(0); } - 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(q); + MPFR_SET_ZERO(q); + if (MPFR_SIGN(q) != MPFR_SIGN(u) * MPFR_SIGN(v)) + MPFR_CHANGE_SIGN(q); + MPFR_RET(0); } - 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); - + MPFR_CLEAR_INF(q); /* clear Inf flag */ if (!MPFR_NOTZERO(v)) { if (!MPFR_NOTZERO(u)) - { MPFR_SET_NAN(r); return; } + { + MPFR_SET_NAN(q); MPFR_RET(1); + } else { - MPFR_SET_INF(r); - if (MPFR_SIGN(r) != MPFR_SIGN(v) * MPFR_SIGN(u)) - MPFR_CHANGE_SIGN(r); - return; + MPFR_SET_INF(q); + if (MPFR_SIGN(q) != MPFR_SIGN(v) * MPFR_SIGN(u)) + MPFR_CHANGE_SIGN(q); + MPFR_RET(0); } } - if (!MPFR_NOTZERO(u)) { MPFR_SET_ZERO(r); return; } + if (!MPFR_NOTZERO(u)) + { + MPFR_SET_ZERO(q); MPFR_RET(0); + } + + sign_quotient = ((MPFR_SIGN(u) * MPFR_SIGN(v) > 0) ? 1 : -1); + if (sign_quotient * MPFR_SIGN(q) < 0) { MPFR_CHANGE_SIGN(q); } + + /************************************************************************** + * * + * End of the part concerning special values. * + * * + **************************************************************************/ + up = MPFR_MANT(u); vp = MPFR_MANT(v); -#ifdef DEBUG - printf("Entering division : "); - for(k = usize - 1; k >= 0; k--) { printf("%lu ", up[k]); } - printf(" by "); - for(k = vsize - 1; k >= 0; k--) { printf("%lu ", vp[k]); } - printf(".\n"); -#endif - - /* Compare the mantissas */ - mult = mpn_cmp(up, vp, (usize > vsize ? vsize : usize)); - if (mult == 0 && vsize > usize) + TMP_MARK (marker); + usize = MPFR_ESIZE(u); + vsize = MPFR_ESIZE(v); + + /************************************************************************** + * * + * First try to use only part of u, v. If this is not sufficient, * + * use the full u and v, to avoid long computations eg. in the case * + * u = v. * + * * + **************************************************************************/ + + /* The dividend is a, length asize. The divisor is b, length bsize. */ + + qsize = (MPFR_PREC(q) + 3)/BITS_PER_MP_LIMB + 1; + if (vsize < qsize) + { + bsize = vsize; + bp = vp; + } + else { - vn = vsize - usize; - while (vn >= 0) if (vp[vn--]) { mult = 1; break; } - /* On peut diagnostiquer ici pour pas cher le cas u = v */ + bsize = qsize; + bp = (mp_srcptr)vp + vsize - qsize; } - else { mult = (mult < 0 ? 1 : 0); } + + asize = bsize + qsize; + ap = (mp_ptr) TMP_ALLOC(asize * BYTES_PER_MP_LIMB); + if (asize > usize) + { + MPN_COPY(ap + asize - usize, up, usize); + MPN_ZERO(ap, asize - usize); + } + else + MPN_COPY(ap, up + usize - asize, asize); + + /* Allocate limbs for quotient and remainder. */ + qp = (mp_ptr) TMP_ALLOC ((qsize + 1) * BYTES_PER_MP_LIMB); + rp = (mp_ptr) TMP_ALLOC (bsize * BYTES_PER_MP_LIMB); + rsize = bsize; - 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. */ + mpn_tdiv_qr(qp, rp, 0, ap, asize, bp, bsize); + + /* Estimate number of correct bits. */ - do - { - TMP_MARK (marker); + err = qsize * BITS_PER_MP_LIMB; + if (bsize < vsize) err -= 2; else if (asize < usize) err --; - rexp = MPFR_EXP(u) - MPFR_EXP(v); - - err = rsize*BITS_PER_MP_LIMB; - if (rsize < vsize) { err-=2; } - if (rsize < usize) { err--; } - if (err > rrsize * BITS_PER_MP_LIMB) - { err = rrsize * BITS_PER_MP_LIMB; } - - 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; - rp = (mp_ptr) TMP_ALLOC ((rrsize+1) * BYTES_PER_MP_LIMB); + /* We want to check if rounding is possible, but without normalizing + because we might have to divide again if rounding is impossible, or + if the result might be exact. We have however to mimic normalization */ - if (vsize >= 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); - } + if (qp[qsize] != 0) { sh = -1; } + else { count_leading_zeros(sh, qp[qsize - 1]); } + + /* + To detect asap if the result is inexact, so as to avoid doing the + division completely, we perform the following check : + + - if rnd_mode == GMP_RNDN, and the result is exact, we are unable + to round simultaneously to zero and to infinity ; + + - if rnd_mode == GMP_RNDN, and if we can round to zero with one extra + bit of precision, we can decide rounding. Hence in that case, check + as in the case of GMP_RNDN, with one extra bit. Note that in the case + of close to even rounding we shall do the division completely, but + this is necessary anyway : we need to know whether this is really + even rounding or not. + */ + + if (rnd_mode == GMP_RNDN) + { + rnd_mode1 = GMP_RNDZ; + near = 1; + } + else + { + rnd_mode1 = rnd_mode; + near = 0; + } - if (usize >= rsize) { - MPN_COPY (tp, up + usize - rsize, rsize); - } - else { - MPN_COPY (tp + rsize - usize, up, usize); - MPN_ZERO (tp, rsize - usize); - } + sh += near; + can_round = mpfr_can_round_raw(qp, qsize + 1, sign_quotient, err + sh + + BITS_PER_MP_LIMB, GMP_RNDN, rnd_mode1, + MPFR_PREC(q) + sh + BITS_PER_MP_LIMB); - /* Do the real job */ - -#ifdef DEBUG - printf("Dividing : "); - for(k = rsize - 1; k >= 0; k--) { printf("%lu ", tp[k]); } - printf(" by "); - for(k = rsize - 1; k >= 0; k--) { printf("%lu ", tmp[k]); } - printf(".\n"); -#endif - -#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"); - printf("Quotient : "); - for(k = rrsize - 1; k >= 0; k--) { printf("%lu ", rp[k]); } - printf("Remainder : "); - for(k = rsize - 1; k >= 0; k--) { printf("%lu ", tp[k]); } - printf("(q_limb = %lu)\n", q_limb); -#endif - - /* msb-normalize the result */ - - if (q_limb) + switch (rnd_mode1) + { + case GMP_RNDU : rnd_mode2 = GMP_RNDD; break; + case GMP_RNDD : rnd_mode2 = GMP_RNDU; break; + case GMP_RNDZ : rnd_mode2 = sign_quotient == 1 ? GMP_RNDU : GMP_RNDD; + break; + default : rnd_mode2 = GMP_RNDZ; + } + + can_round2 = mpfr_can_round_raw(qp, qsize + 1, sign_quotient, err + sh + + BITS_PER_MP_LIMB, GMP_RNDN, rnd_mode2, + MPFR_PREC(q) + sh + BITS_PER_MP_LIMB); + + sh -= near; + + /* If either can_round or can_round2 is 0, either we cannot round or + the result might be exact. If asize >= usize and bsize >= vsize, we + can just check this by looking at the remainder. Otherwise, we + have to correct our first approximation. */ + + if ((!can_round || !can_round2) && (asize < usize || bsize < vsize)) + { + int b = 0; + mp_ptr rem, rem2; + + /************************************************************************** + * * + * The attempt to use only part of u and v failed. We first compute a * + * correcting term, then perform the full division. * + * Put u = uhi + ulo, v = vhi + vlo. We have uhi = vhi * rp + tp, * + * thus u - v * rp = tp + ulo - rp*vlo, that we shall divide by v. * + * * + **************************************************************************/ + + rsize = qsize + 1 + + (usize - asize > vsize - bsize + ? usize - asize + : vsize - bsize); + + /* + TODO : One operand is probably enough, but then we have to + perform one further comparison (compute first vlo * q, + try to substract r, try to substract ulo. Which is best ? + NB : ulo and r do not overlap. Draw advantage of this + [eg. HI(vlo*q) = r => compare LO(vlo*q) with b.] + */ + + rem = TMP_ALLOC(rsize * BYTES_PER_MP_LIMB); + rem2 = TMP_ALLOC(rsize * BYTES_PER_MP_LIMB); + + rem[rsize - 1] = rem2 [rsize - 1] = 0; + + if (bsize < vsize) { - count_leading_zeros(k, q_limb); - mpn_rshift(rp, rp, rrsize, BITS_PER_MP_LIMB - k); - rp[rrsize - 1] |= (q_limb << k); - rexp += BITS_PER_MP_LIMB - k; + /* Compute vlo * q */ + if (qsize + 1 > vsize - bsize) + mpn_mul(rem + rsize - vsize - qsize - 1 + bsize, + qp, qsize + 1, vp, vsize - bsize); + else + mpn_mul(rem + rsize - vsize - qsize - 1 + bsize, + vp, vsize - bsize, qp, qsize + 1); + + MPN_ZERO(rem, rsize - vsize - qsize - 1 + bsize); } - else - { - count_leading_zeros(k, rp[rrsize - 1]); - if (k) { mpn_lshift(rp, rp, rrsize, k); } - rexp -= k; + else MPN_ZERO(rem, rsize); + + /* Compute ulo + r. The two of them do not overlap. */ + MPN_COPY(rem2 + rsize - 1 - qsize, rp, bsize); + + if (qsize + 1 > bsize) + MPN_ZERO(rem2 + rsize - 1 - qsize + bsize, qsize + 1 - bsize); + + if (asize < usize) + { + MPN_COPY(rem2 + rsize - 1 - qsize - usize + asize, + up, usize - asize); + MPN_ZERO(rem2, rsize - 1 - qsize - usize + asize); } + else + MPN_ZERO(rem2, rsize - 1 - qsize); - can_round = (mpfr_can_round_raw(rp, rrsize, sign_quotient, err, - GMP_RNDN, rnd_mode, MPFR_PREC(r)) - || (usize == rsize && vsize == rsize && - mpfr_can_round_raw(rp, rrsize, sign_quotient, err, - 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)) + b = 0; + if (mpn_cmp(rem2, rem, rsize) >= 0) { -#ifdef DEBUG - printf("Increasing the precision.\n"); -#endif - 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; + /* Positive correction is at most 1. */ + + mpn_sub_n(rem, rem2, rem, rsize); + if (rem[rsize - 1] != 0 || + mpn_cmp(rem + rsize - vsize - 1, vp, vsize) >= 0) + { + rem[rsize - 1] -= + mpn_sub_n(rem + rsize - vsize - 1, + rem + rsize - vsize - 1, + vp, vsize); + qp[qsize] -= mpn_add_1(qp, qp, qsize, 1); + } } + else + { + /* Negative correction is at most 3 */ + do + { + b++; + rem2[rsize - 1] += + mpn_add_n(rem2 + rsize - vsize - 1, + rem2 + rsize - vsize - 1, vp, vsize); + } + while (mpn_cmp(rem2, rem, rsize) < 0); + + qp[qsize] -= mpn_sub_1(qp, qp, qsize, b); + mpn_sub_n(rem, rem2, rem, rsize); + } + + if (qp[qsize] != 0) + sh = -1; + else + count_leading_zeros(sh, qp[qsize - 1]); + + err = BITS_PER_MP_LIMB * qsize; + rp = rem; } - while (!can_round && (rsize < usize || rsize < vsize) - && (rsize++) && (rrsize++)); + + /************************************************************************** + * * + * Final stuff (rounding and so.) * + * From now on : qp is the quotient [size qsize], rp the remainder * + * [size rsize]. * + **************************************************************************/ - /* 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; + qexp = MPFR_EXP(u) - MPFR_EXP(v); - if (can_round) + if (qp[qsize] != 0) + /* Hack : qp[qsize] is 0, 1 or 2, hence if not 0, = 2^(qp[qsize] - 1). */ { - cc = mpfr_round_raw(rp, rp, err, (sign_quotient == -1 ? 1 : 0), - MPFR_PREC(r), rnd_mode); + near = mpn_rshift(qp, qp, qsize, qp[qsize]); + qp[qsize - 1] |= MP_LIMB_T_HIGHBIT; qexp += qp[qsize]; } - 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) - { - 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 */ + else + { + near = 0; + if (sh != 0) + { + mpn_lshift(qp, qp, qsize, sh); + qexp -= sh; + } + } + + cc = mpfr_round_raw_generic(qp, qp, err, (sign_quotient == -1 ? 1 : 0), + MPFR_PREC(q), rnd_mode, &inex, 1); + + qp += qsize - MPFR_ESIZE(q); /* 0 or 1 */ + qsize = MPFR_ESIZE(q); + + /* + At that point, either we were able to round from the beginning, + and know thus that the result is inexact. + + Or we have performed a full division. In that case, we might still + be wrong if both + - the remainder is nonzero ; + - we are rounding to infinity or to nearest (the nasty case of even + rounding). + - inex = 0, meaning that the non-significant bits of the quotients are 0, + except when rounding to nearest (the nasty case of even rounding again). + */ + + if (!can_round || !can_round2) /* Lazy case. */ + { + if (inex == 0) + { + k = rsize - 1; + + /* If a bit has been shifted out during normalization, hence + the remainder is nonzero. */ + if (near == 0) + while (k >= 0) { if (rp[k]) break; k--; } + + if (k >= 0) /* Remainder is nonzero. */ { - 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)) + if ((rnd_mode == GMP_RNDD && sign_quotient == -1) + || (rnd_mode == GMP_RNDU && sign_quotient == 1)) + /* Rounding to infinity. */ { - cc = mpn_add_1(rp + nw, rp + nw, rrsize, - ((mp_limb_t)1) << rw); + inex = sign_quotient; + cc = 1; } + /* rounding to zero. */ + else inex = -sign_quotient; } - /* 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 (cc) { - mpn_rshift(rp, rp, rrsize, 1); - rp[rrsize-1] |= (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); - MPFR_EXP(r)++; - } - - 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); - + } + else /* We might have to correct an even rounding if remainder + is nonzero and if even rounding was towards 0. */ + if (rnd_mode == GMP_RNDN && (inex == MPFR_EVEN_INEX + || inex == -MPFR_EVEN_INEX)) + { + k = rsize - 1; + + /* If a bit has been shifted out during normalization, hence + the remainder is nonzero. */ + if (near == 0) + while (k >= 0) + { + if (rp[k]) + break; + k--; + } + + if (k >= 0) /* In fact the quotient is larger than expected */ + { + inex = sign_quotient; /* To infinity, finally. */ + cc = 1; + } + } + } + + /* Final modification due to rounding */ + if (cc) + { + sh = MPFR_PREC(q) & (BITS_PER_MP_LIMB - 1); + if (sh) + cc = mpn_add_1 (qp, qp, qsize, + MP_LIMB_T_ONE << (BITS_PER_MP_LIMB - sh)); + else + cc = mpn_add_1 (qp, qp, qsize, MP_LIMB_T_ONE); + + if (cc) + { + mpn_rshift (qp, qp, qsize, 1); + qp[qsize-1] |= MP_LIMB_T_HIGHBIT; + qexp++; + } + } + + rw = qsize * BITS_PER_MP_LIMB - MPFR_PREC(q); + MPN_COPY(MPFR_MANT(q), qp, qsize); TMP_FREE (marker); + + MPFR_MANT(q)[0] &= ~((MP_LIMB_T_ONE << rw) - MP_LIMB_T_ONE); + MPFR_EXP(q) = qexp; + + MPFR_RET(inex); } + diff --git a/mpfr/div_2exp.c b/mpfr/div_2exp.c index e518f6518..68284f0a4 100644 --- a/mpfr/div_2exp.c +++ b/mpfr/div_2exp.c @@ -1,20 +1,20 @@ /* mpfr_div_2exp -- divide a floating-point number by a power of two -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -25,20 +25,15 @@ MA 02111-1307, USA. */ #include "mpfr.h" #include "mpfr-impl.h" -void -#if __STDC__ +int 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_ptr y; - mpfr_srcptr x; - unsigned long int n; - mp_rnd_t rnd_mode; -#endif { + int inexact = 0; + /* Important particular case */ - if (y != x) mpfr_set(y, x, rnd_mode); - MPFR_EXP(y) -= n; - return; + if (y != x) + inexact = mpfr_set (y, x, rnd_mode); + return ((MPFR_EXP(y) -= n) < __mpfr_emin) + ? mpfr_set_underflow (y, rnd_mode, MPFR_SIGN(y)) : inexact; } diff --git a/mpfr/div_ui.c b/mpfr/div_ui.c index bf5e94c05..c3986f07d 100644 --- a/mpfr/div_ui.c +++ b/mpfr/div_ui.c @@ -1,20 +1,20 @@ /* mpfr_div_ui -- divide a floating-point number by a machine integer -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -26,24 +26,20 @@ MA 02111-1307, USA. */ #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 int u, mp_rnd_t rnd_mode) -#else -mpfr_div_ui(y, x, u, rnd_mode) - mpfr_ptr y; - mpfr_srcptr x; - unsigned long int u; - mp_rnd_t rnd_mode; -#endif +mpfr_div_ui (mpfr_ptr y, mpfr_srcptr x, unsigned long int u, mp_rnd_t rnd_mode) { - int xn, yn, dif, sh, i; mp_limb_t *xp, *yp, *tmp, c, d; + long int xn, yn, dif, sh, i; + mp_limb_t *xp, *yp, *tmp, c, d; + int inexact, middle = 1; TMP_DECL(marker); - if (MPFR_IS_NAN(x)) { MPFR_SET_NAN(y); return 1; } + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(y); + MPFR_RET_NAN; + } MPFR_CLEAR_NAN(y); /* clear NaN flag */ @@ -53,105 +49,138 @@ mpfr_div_ui(y, x, u, rnd_mode) 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 (u == 0) { - if (MPFR_IS_ZERO(x)) { MPFR_SET_NAN(y) ; return 1; } - else + if (MPFR_IS_ZERO(x)) /* 0/0 is NaN */ + { + MPFR_SET_NAN(y); + MPFR_RET_NAN; + } + else /* x/0 is Inf */ { - MPFR_SET_INF(y); MPFR_SET_SAME_SIGN(y, x); return 0; - /* TODO: semantique de la division dans ce cas-la aussi ? */ + MPFR_SET_INF(y); + MPFR_SET_SAME_SIGN(y, x); + return 0; } } MPFR_CLEAR_INF(y); + + if (MPFR_IS_ZERO(x)) + { + MPFR_SET_ZERO(y); + return 0; + } TMP_MARK(marker); - xn = (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB + 1; - yn = (MPFR_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 = 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); + if (MPFR_SIGN(x) * MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN(y); - dif = yn+1-xn; -#ifdef DEBUG - printf("dif=%d u=%lu xn=%d\n",dif,u,xn); - printf("x="); mpfr_print_raw(x); putchar('\n'); -#endif + dif = yn + 1 - xn; /* we need to store yn+1 = xn + dif limbs of the quotient */ /* don't use tmp=yp since the mpn_lshift call below requires yp >= tmp+1 */ - tmp=TMP_ALLOC((yn+1)*BYTES_PER_MP_LIMB); + tmp = TMP_ALLOC((yn + 1) * BYTES_PER_MP_LIMB); c = (mp_limb_t) u; - if (dif>=0) { -#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; - 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; MPFR_EXP(y) -= BITS_PER_MP_LIMB; } + if (dif >= 0) + c = mpn_divrem_1 (tmp, dif, xp, xn, c); /* used all the dividend */ + else /* dif < 0 i.e. xn > yn, don't use the (-dif) low limbs from x */ + c = mpn_divrem_1 (tmp, 0, xp - dif, yn + 1, c); + + inexact = (c != 0); + if (rnd_mode == GMP_RNDN) + { + if (2 * c < (mp_limb_t) u) + middle = -1; + else if (2 * c > (mp_limb_t) u) + middle = 1; + else + middle = 0; /* exactly in the middle */ + } + for (i=0; ((inexact == 0) || (middle == 0)) && (i < -dif); i++) + if (xp[i]) + inexact = middle = 1; /* larger than middle */ + + if (tmp[yn] == 0) /* high limb is zero */ + { + tmp--; + sh = 0; + MPFR_EXP(y) -= BITS_PER_MP_LIMB; + } + + /* now we have yn limbs starting from tmp[1], with tmp[yn]<>0 */ + /* 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); - MPFR_EXP(y) -= sh; - } - else MPN_COPY(yp, tmp+1, yn); -#ifdef DEBUG - printf("y="); mpfr_print_raw(y); putchar('\n'); -#endif - - sh = yn*BITS_PER_MP_LIMB - MPFR_PREC(y); + if (sh) + { + mpn_lshift (yp, tmp + 1, yn, sh); + yp[0] += tmp[0] >> (BITS_PER_MP_LIMB - sh); + middle = middle || ((tmp[0] << sh) != 0); + inexact = inexact || ((tmp[0] << sh) != 0); + MPFR_EXP(y) -= sh; + } + else + MPN_COPY(yp, tmp + 1, yn); + + 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); + d = *yp & ((MP_LIMB_T_ONE << sh) - MP_LIMB_T_ONE); *yp ^= d; /* set to zero lowest sh bits */ TMP_FREE(marker); - if ((c | d)==0) { - for (i=0; i<-dif && xp[i]==0; i++); - if (i>=-dif) return 0; /* result is exact */ - } - - switch (rnd_mode) { - case GMP_RNDZ: - return 1; /* result is inexact */ - case GMP_RNDU: - if (MPFR_SIGN(y)>0) mpfr_add_one_ulp(y); - return 1; /* result is inexact */ - case GMP_RNDD: - 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; - else if (d > ((mp_limb_t)1 << (sh-1))) { - mpfr_add_one_ulp(y); - } - else { /* d = (mp_limb_t)1 << (sh-1) */ - if (c) mpfr_add_one_ulp(y); - else { - for (i=0; i<-dif && xp[i]==0; i++); - if (i<-dif) mpfr_add_one_ulp(y); - else { /* exactly in the middle */ - if (*yp & ((mp_limb_t)1 << sh)) mpfr_add_one_ulp(y); + if ((d == 0) && (inexact == 0)) + return 0; /* result is exact */ + + switch (rnd_mode) + { + case GMP_RNDZ: + MPFR_RET(-MPFR_SIGN(x)); /* result is inexact */ + + case GMP_RNDU: + if (MPFR_SIGN(y) > 0) + mpfr_add_one_ulp (y); + MPFR_RET(1); /* result is inexact */ + + case GMP_RNDD: + if (MPFR_SIGN(y) < 0) + mpfr_add_one_ulp (y); + MPFR_RET(-1); /* result is inexact */ + + case GMP_RNDN: + if (sh && d < (MP_LIMB_T_ONE << (sh - 1))) + MPFR_RET(-MPFR_SIGN(x)); + else if (sh && d > (MP_LIMB_T_ONE << (sh - 1))) + { + mpfr_add_one_ulp (y); + MPFR_RET(MPFR_SIGN(x)); } + else /* sh = 0 or d = 1 << (sh-1) */ + { + /* we are in the middle if: + (a) sh > 0 and inexact == 0 + (b) sh=0 and middle=1 + */ + if ((sh && inexact) || (!sh && (middle > 0)) || (*yp & (MP_LIMB_T_ONE << sh))) + { + mpfr_add_one_ulp (y); + MPFR_RET(MPFR_SIGN(x)); + } + else + MPFR_RET(-MPFR_SIGN(x)); } } - return 1; - } - return 0; /* to prevent warning from gcc */ + MPFR_RET(inexact); /* should never go here */ } diff --git a/mpfr/dump.c b/mpfr/dump.c index a7180bcac..017298e9a 100644 --- a/mpfr/dump.c +++ b/mpfr/dump.c @@ -1,44 +1,34 @@ /* 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) 1999, 2001 Free Software Foundation, Inc. +(Copied from the GNU MP Library.) +This file is part of the MPFR Library. -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 +The MPFR 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 +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 +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 Library General Public License -along with the GNU MP Library; see the file COPYING.LIB. If not, write to +You should have received a copy of the GNU Lesser 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 <strings.h> +#include <string.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; @@ -1,23 +1,22 @@ /* mpfr_eq -- Compare two floats up to a specified bit #. -Copied from mpf_eq. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. +(Copied from GNU MP, file mpf_eq.) -Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc. +This file is part of the MPFR Library. -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 +The MPFR 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 +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 +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 Library General Public License -along with the GNU MP Library; see the file COPYING.LIB. If not, write to +You should have received a copy of the GNU Lesser 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. */ @@ -28,14 +27,7 @@ MA 02111-1307, USA. */ #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; diff --git a/mpfr/euler.c b/mpfr/euler.c new file mode 100644 index 000000000..eb36fe6e6 --- /dev/null +++ b/mpfr/euler.c @@ -0,0 +1,171 @@ +/* mpfr_const_euler -- Euler's constant + +Copyright (C) 2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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" + +static void mpfr_const_euler_S _PROTO ((mpfr_ptr, unsigned long)); +static void mpfr_const_euler_R _PROTO ((mpfr_ptr, unsigned long)); + +int +mpfr_const_euler (mpfr_t x, mp_rnd_t rnd) +{ + mp_prec_t prec = MPFR_PREC(x), m, log2m; + mpfr_t y, z; + unsigned long n; + + log2m = _mpfr_ceil_log2 ((double) prec); + m = prec + log2m; + + mpfr_init (y); + mpfr_init (z); + + do + { + m += BITS_PER_MP_LIMB; + n = 1 + (unsigned long)((double) m * LOG2 / 2.0); + if (n < 9) + n = 9; + MPFR_ASSERTD (n >= 9); + mpfr_set_prec (y, m + log2m); + mpfr_set_prec (z, m + log2m); + mpfr_const_euler_S (y, n); + mpfr_set_ui (z, n, GMP_RNDN); + mpfr_log (z, z, GMP_RNDD); + mpfr_sub (y, y, z, GMP_RNDN); /* S'(n) - log(n) */ + mpfr_set_prec (z, m); + mpfr_const_euler_R (z, n); + mpfr_sub (y, y, z, GMP_RNDN); + } + while (!mpfr_can_round (y, m - 3, GMP_RNDN, rnd, prec)); + + mpfr_set (x, y, rnd); + + mpfr_clear (y); + mpfr_clear (z); + + return 1; /* always inexact */ +} + +/* computes S(n) = sum(n^k*(-1)^(k-1)/k!/k, k=1..ceil(4.319136566 * n)) + with an error of at most ulp(x). + [S(n) >= 2 for n >= 5] + */ +void +mpfr_const_euler_S (mpfr_t x, unsigned long n) +{ + unsigned long N, k, m; + mpz_t a, s, t; + + N = (long) (ALPHA * (double) n + 1.0); /* ceil(alpha * n) */ + + m = MPFR_PREC(x) + (unsigned long) ((double) n / LOG2) + + _mpfr_ceil_log2 ((double) N) + 1; + + mpz_init_set_ui (a, 1); + mpz_mul_2exp (a, a, m); /* a=-2^m where m is the precision of x */ + mpz_init_set_ui (s, 0); + mpz_init (t); + + /* here, a and s are exact */ + for (k = 1; k <= N; k++) + { + mpz_mul_ui (a, a, n); + mpz_div_ui (a, a, k); + mpz_div_ui (t, a, k); + if (k % 2) + mpz_add (s, s, t); + else + mpz_sub (s, s, t); + } + + /* the error on s is at most N (e^n + 1), + thus that the error on x is at most one ulp */ + + mpfr_set_z (x, s, GMP_RNDD); + mpfr_div_2exp (x, x, m, GMP_RNDD); + + mpz_clear (a); + mpz_clear (s); + mpz_clear (t); +} + +/* computes R(n) = exp(-n)/n * sum(k!/(-n)^k, k=0..n-2) + with error at most 4*ulp(x). Assumes n>=2. + Since x <= exp(-n)/n <= 1/8, then 4*ulp(x) <= ulp(1). +*/ +void +mpfr_const_euler_R (mpfr_t x, unsigned long n) +{ + unsigned long k, m; + mpz_t a, s; + mpfr_t y; + + MPFR_ASSERTN (n >= 2); /* ensures sum(k!/(-n)^k, k=0..n-2) >= 2/3 */ + + /* as we multiply the sum by exp(-n), we need only PREC(x) - n/LOG2 bits */ + m = MPFR_PREC(x) - (unsigned long) ((double) n / LOG2); + + mpz_init_set_ui (a, 1); + mpz_mul_2exp (a, a, m); + mpz_init_set (s, a); + + for (k = 1; k <= n; k++) + { + mpz_mul_ui (a, a, k); + mpz_div_ui (a, a, n); + /* the error e(k) on a is e(k) <= 1 + k/n*e(k-1) with e(0)=0, + i.e. e(k) <= k */ + if (k % 2) + mpz_sub (s, s, a); + else + mpz_add (s, s, a); + } + /* the error on s is at most 1+2+...+n = n*(n+1)/2 */ + mpz_div_ui (s, s, n); /* err <= 1 + (n+1)/2 */ + if (MPFR_PREC(x) < mpz_sizeinbase(s, 2)) + { + fprintf (stderr, "prec(x) is too small in mpfr_const_euler_R\n"); + exit (1); + } + mpfr_set_z (x, s, GMP_RNDD); /* exact */ + mpfr_div_2exp (x, x, m, GMP_RNDD); + /* now x = 1/n * sum(k!/(-n)^k, k=0..n-2) <= 1/n */ + /* err(x) <= (n+1)/2^m <= (n+1)*exp(n)/2^PREC(x) */ + + mpfr_init2 (y, m); + mpfr_set_si (y, -n, GMP_RNDD); /* assumed exact */ + mpfr_exp (y, y, GMP_RNDD); /* err <= ulp(y) <= exp(-n)*2^(1-m) */ + mpfr_mul (x, x, y, GMP_RNDD); + /* err <= ulp(x) + (n + 1 + 2/n) / 2^prec(x) + <= ulp(x) + (n + 1 + 2/n) ulp(x)/x since x*2^(-prec(x)) < ulp(x) + <= ulp(x) + (n + 1 + 2/n) 3/(2n) ulp(x) since x >= 2/3*n for n >= 2 + <= 4 * ulp(x) for n >= 2 */ + mpfr_clear (y); + + mpz_clear (a); + mpz_clear (s); +} diff --git a/mpfr/exceptions.c b/mpfr/exceptions.c new file mode 100644 index 000000000..26b99c0c2 --- /dev/null +++ b/mpfr/exceptions.c @@ -0,0 +1,230 @@ +/* Exception flags and utilities. + +Copyright (C) 2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +unsigned int __mpfr_flags = 0; + +mp_exp_t __mpfr_emin = MPFR_EMIN_DEFAULT; +mp_exp_t __mpfr_emax = MPFR_EMAX_DEFAULT; + +#undef mpfr_get_emin + +mp_exp_t +mpfr_get_emin (void) +{ + return __mpfr_emin; +} + +#undef mpfr_set_emin + +int +mpfr_set_emin (mp_exp_t exponent) +{ + if (exponent >= MPFR_EMIN_MIN && exponent <= MPFR_EMIN_MAX) + { + __mpfr_emin = exponent; + return 0; + } + else + { + return 1; + } +} + +#undef mpfr_get_emax + +mp_exp_t +mpfr_get_emax (void) +{ + return __mpfr_emax; +} + +#undef mpfr_set_emax + +int +mpfr_set_emax (mp_exp_t exponent) +{ + if (exponent >= MPFR_EMAX_MIN && exponent <= MPFR_EMAX_MAX) + { + __mpfr_emax = exponent; + return 0; + } + else + { + return 1; + } +} + +#undef mpfr_clear_flags + +void +mpfr_clear_flags (void) +{ + __mpfr_flags = 0; +} + +#undef mpfr_clear_underflow + +void +mpfr_clear_underflow (void) +{ + __mpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_UNDERFLOW; +} + +#undef mpfr_clear_overflow + +void +mpfr_clear_overflow (void) +{ + __mpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_OVERFLOW; +} + +#undef mpfr_clear_nanflag + +void +mpfr_clear_nanflag (void) +{ + __mpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_NAN; +} + +#undef mpfr_clear_inexflag + +void +mpfr_clear_inexflag (void) +{ + __mpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_INEXACT; +} + +#undef mpfr_check_range + +int +mpfr_check_range (mpfr_ptr x, mp_rnd_t rnd_mode) +{ + if (MPFR_IS_FP(x) && MPFR_NOTZERO(x)) + { /* x is a non-zero FP */ + mp_exp_t exp = MPFR_EXP(x); + if (exp < __mpfr_emin) + return mpfr_set_underflow(x, rnd_mode, MPFR_SIGN(x)); + if (exp > __mpfr_emax) + return mpfr_set_overflow(x, rnd_mode, MPFR_SIGN(x)); + } + return 0; +} + +#undef mpfr_underflow_p + +int +mpfr_underflow_p (void) +{ + return __mpfr_flags & MPFR_FLAGS_UNDERFLOW; +} + +#undef mpfr_overflow_p + +int +mpfr_overflow_p (void) +{ + return __mpfr_flags & MPFR_FLAGS_OVERFLOW; +} + +#undef mpfr_nanflag_p + +int +mpfr_nanflag_p (void) +{ + return __mpfr_flags & MPFR_FLAGS_NAN; +} + +#undef mpfr_inexflag_p + +int +mpfr_inexflag_p (void) +{ + return __mpfr_flags & MPFR_FLAGS_INEXACT; +} + +#undef mpfr_set_underflow + +int +mpfr_set_underflow (mpfr_ptr x, mp_rnd_t rnd_mode, int sign) +{ + int inex; + + MPFR_CLEAR_FLAGS(x); + if ((rnd_mode == GMP_RNDU && sign > 0) + || (rnd_mode == GMP_RNDD && sign < 0)) + { + mp_size_t xn; + mp_limb_t *xp; + + MPFR_EXP(x) = __mpfr_emin; + xn = (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB; + xp = MPFR_MANT(x); + xp[xn] = MP_LIMB_T_HIGHBIT; + MPN_ZERO(xp, xn); + inex = 1; + } + else + { + MPFR_SET_ZERO(x); + inex = -1; + } + if (MPFR_SIGN(x) != sign) + MPFR_CHANGE_SIGN(x); + __mpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_UNDERFLOW; + return sign > 0 ? inex : -inex; +} + +#undef mpfr_set_overflow + +int +mpfr_set_overflow (mpfr_ptr x, mp_rnd_t rnd_mode, int sign) +{ + int inex; + + MPFR_CLEAR_FLAGS(x); + if ((rnd_mode == GMP_RNDU && sign < 0) + || (rnd_mode == GMP_RNDD && sign > 0)) + { + mp_size_t xn, i; + mp_limb_t *xp; + + MPFR_EXP(x) = __mpfr_emax; + xn = (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB; + xp = MPFR_MANT(x); + for (i = 0; i <= xn; i++) + xp[i] = MP_LIMB_T_MAX; + inex = -1; + } + else + { + MPFR_SET_INF(x); + inex = 1; + } + if (MPFR_SIGN(x) != sign) + MPFR_CHANGE_SIGN(x); + __mpfr_flags |= MPFR_FLAGS_INEXACT | MPFR_FLAGS_OVERFLOW; + return sign > 0 ? inex : -inex; +} diff --git a/mpfr/exp.c b/mpfr/exp.c index 4dfb614c3..c2130880f 100644 --- a/mpfr/exp.c +++ b/mpfr/exp.c @@ -1,20 +1,21 @@ /* mpfr_exp -- exponential of a floating-point number -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999-2001 Free Software Foundation. +Contributed by the Spaces project. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -27,68 +28,98 @@ MA 02111-1307, USA. */ /* #define DEBUG */ -extern int mpfr_exp2 _PROTO((mpfr_ptr, mpfr_srcptr, mp_rnd_t)); +extern int mpfr_exp_2 _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 number of operations = O(K+prec(r)/K) */ int -#if __STDC__ 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; - mp_rnd_t rnd_mode; -#endif { - int expx, precy; + int expx, precy; + double d; - if (MPFR_IS_NAN(x)) { MPFR_SET_NAN(y); return 1; } + 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; + 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); + } + return 0; } MPFR_CLEAR_INF(y); - if (!MPFR_NOTZERO(x)) { mpfr_set_ui(y, 1, GMP_RNDN); return 0; } + 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 (MPFR_SIGN(x)>0) { printf("+infinity"); return 1; } - else { MPFR_SET_ZERO(y); return 1; } - } + /* result is +Inf when exp(x) >= 2^(__mpfr_emax), i.e. + x >= __mpfr_emax * log(2) */ + d = mpfr_get_d (x); + if (d >= (double) __mpfr_emax * LOG2) + { + MPFR_SET_INF(y); + if (MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN(y); + return 1; /* overflow */ + } + + /* result is 0 when exp(x) < 1/2*2^(__mpfr_emin), i.e. + x < (__mpfr_emin-1) * LOG2 */ + if (d < ((double) __mpfr_emin - 1.0) * LOG2) + { + MPFR_SET_ZERO(y); + if (MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN(y); + return 1; /* underflow */ + } /* 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; } - - 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; -} + 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); + return 1; + } + else if (signx < 0 && (rnd_mode == GMP_RNDD || rnd_mode == GMP_RNDZ)) + { + mpfr_sub_one_ulp (y); + return -1; + } + return -signx; + } + if (precy > 13000) + return mpfr_exp3 (y, x, rnd_mode); /* O(M(n) log(n)^2) */ + else + return mpfr_exp_2 (y, x, rnd_mode); /* O(n^(1/3) M(n)) */ +} diff --git a/mpfr/exp2.c b/mpfr/exp2.c index 0bd5c5bc5..3768778f5 100644 --- a/mpfr/exp2.c +++ b/mpfr/exp2.c @@ -1,433 +1,118 @@ -/* 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)) +/* mpfr_exp2 -- power of 2 function 2^y -Copyright (C) 1999-2000, 2001 Free Software Foundation. +Copyright (C) 2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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 _PROTO ((mpz_t, mpfr_srcptr, int, int*)); -int mpfr_exp2_aux2 _PROTO ((mpz_t, mpfr_srcptr, int, int*)); -mp_exp_t mpz_normalize _PROTO ((mpz_t, mpz_t, int)); -int mpz_normalize2 _PROTO ((mpz_t, mpz_t, int, int)); -int mpfr_exp2 _PROTO ((mpfr_ptr, mpfr_srcptr, mp_rnd_t)); + /* The computation of y=pow(2,z) is done by -/* 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. + y=exp(z*log(2))=2^z */ -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); + int inexact =0; - /* 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 (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(y); + return 1; + } - /* 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)) */ + MPFR_CLEAR_NAN(y); + + if (MPFR_IS_INF(x)) + { + if (MPFR_SIGN(x) < 0) + { + MPFR_SET_ZERO(y); + if (MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN(y); + return 0; + } + else + { + MPFR_SET_INF(y); + if(MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN(y); + return 0; + } + } -#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 */ + /* 2^0 = 1 */ + if(mpfr_cmp_ui(x,0)==0) + { + return mpfr_set_ui(y,1,rnd_mode); + } - 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 */ + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t t, te; -#ifdef DEBUG - printf("l=%d q=%d (K+l)*q^2=%1.3e\n", l, q, (K+l)*(double)q*q); -#endif + /* Declaration of the size variable */ + mp_prec_t Nx = MPFR_PREC(x); /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ - 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; - TMP_FREE(marker); /* don't need ss anymore */ + mp_prec_t Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt=Nt+5+_mpfr_ceil_log2(Nt); - 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 + /* initialise of intermediary variable */ + mpfr_init(t); + mpfr_init(te); - 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); + /* First computation of cosh */ + do { - mpfr_set(y, s, rnd_mode); + /* reactualisation of the precision */ + mpfr_set_prec(t,Nt); + mpfr_set_prec(te,Nt); - mpfr_clear(r); mpfr_clear(s); mpfr_clear(t); - return 1; -} + /* compute exp(x*ln(2))*/ + mpfr_const_log2(t,GMP_RNDU); /* ln(2) */ + mpfr_mul(te,x,t,GMP_RNDU); /* x*ln(2) */ + mpfr_exp(t,te,GMP_RNDN); /* exp(x*ln(2))*/ -/* 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); + /* estimate of the error -- see pow function in algorithms.ps*/ + err=Nt-(MPFR_EXP(te)+2); - 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; -} + /* actualisation of the precision */ + Nt += 10; -/* 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; + } while ((err<0) || !mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny)); + + inexact = mpfr_set(y,t,rnd_mode); + mpfr_clear(t); + mpfr_clear(te); } - 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); + return inexact; - TMP_FREE(marker); - mpz_clear(tmp); - return l; } diff --git a/mpfr/exp3.c b/mpfr/exp3.c index 175ef143d..8441850b9 100644 --- a/mpfr/exp3.c +++ b/mpfr/exp3.c @@ -1,20 +1,20 @@ /* mpfr_exp -- exponential of a floating-point number -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -25,21 +25,11 @@ MA 02111-1307, USA. */ #include "mpfr.h" #include "mpfr-impl.h" -/* #define DEBUG */ - -int mpfr_exp_rational _PROTO ((mpfr_ptr, mpz_srcptr, int, int)); +static int mpfr_exp_rational _PROTO ((mpfr_ptr, mpz_srcptr, int, int)); int mpfr_exp3 _PROTO ((mpfr_ptr, mpfr_srcptr, mp_rnd_t)); -int -#if __STDC__ +static int 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; @@ -129,14 +119,7 @@ mpfr_exp_rational (y, p, r, m) #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; @@ -152,27 +135,10 @@ mpfr_exp3 (y, x, rnd_mode) 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; - } + int logn, inexact = 0; - /* Decomposer x */ - /* on commence par ecrire x = 1.xxxxxxxxxxxxx + /* decompose x */ + /* we first write 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; @@ -181,7 +147,7 @@ mpfr_exp3 (y, x, rnd_mode) 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 */ + /* we shift to get a number less than 1 */ if (ttt > 0) { shift_x = ttt; @@ -195,52 +161,42 @@ mpfr_exp3 (y, x, rnd_mode) k = _mpfr_ceil_log2 ((double) Prec / BITS_PER_MP_LIMB); /* now we have to extract */ - mpfr_init2(t, Prec); - mpfr_init2(tmp, Prec); + 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) */ + /* particular case: we have to compute with x/2^., then + do squarings (this is faster) */ 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; } + mpfr_clear (t); 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); + mpfr_mul (tmp, tmp, tmp, GMP_RNDD); + if (mpfr_can_round (tmp, realprec, GMP_RNDD, rnd_mode, MPFR_PREC(y))) + { + inexact = mpfr_set (y, tmp, rnd_mode); + good = 1; + } + else realprec += 3*logn; - } + mpfr_clear (tmp); } mpz_clear (uk); mpfr_clear(x_copy); - return 0; + return inexact; } diff --git a/mpfr/exp_2.c b/mpfr/exp_2.c new file mode 100644 index 000000000..402919092 --- /dev/null +++ b/mpfr/exp_2.c @@ -0,0 +1,368 @@ +/* mpfr_exp_2 -- 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, 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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" + +static int mpfr_exp2_aux _PROTO ((mpz_t, mpfr_srcptr, int, int*)); +static int mpfr_exp2_aux2 _PROTO ((mpz_t, mpfr_srcptr, int, int*)); +static mp_exp_t mpz_normalize _PROTO ((mpz_t, mpz_t, int)); +static int mpz_normalize2 _PROTO ((mpz_t, mpz_t, int, int)); +int mpfr_exp_2 _PROTO ((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. + */ +static mp_exp_t +mpz_normalize (mpz_t rop, mpz_t z, int q) +{ + 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. +*/ +static int +mpz_normalize2 (mpz_t rop, mpz_t z, int expz, int target) +{ + 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 +mpfr_exp_2 (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode) +{ + int n, expx, K, precy, q, k, l, err, exps, inexact; + mpfr_t r, s, t; mpz_t ss; + TMP_DECL(marker); + + expx = MPFR_EXP(x); + precy = MPFR_PREC(y); +#ifdef DEBUG + printf("MPFR_EXP(x)=%d\n",expx); +#endif + + 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; + TMP_FREE(marker); /* don't need ss anymore */ + + 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); + + inexact = mpfr_set (y, s, rnd_mode); + + mpfr_clear(r); mpfr_clear(s); mpfr_clear(t); + return inexact; +} + +/* 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) +*/ +static int +mpfr_exp2_aux (mpz_t s, mpfr_srcptr r, int q, int *exps) +{ + 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. +*/ +static int +mpfr_exp2_aux2 (mpz_t s, mpfr_srcptr r, int q, int *exps) +{ + 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/expm1.c b/mpfr/expm1.c new file mode 100644 index 000000000..cdb41072d --- /dev/null +++ b/mpfr/expm1.c @@ -0,0 +1,116 @@ +/* mpfr_expm1 -- Compute exp(x)-1 + +Copyright (C) 2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + + /* The computation of expm1 is done by + + expm1(x)=exp(x)-1 + */ + +int +mpfr_expm1 (mpfr_ptr y, mpfr_srcptr x , mp_rnd_t rnd_mode) +{ + + int inexact = 0; + + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(y); + return 1; + } + MPFR_CLEAR_NAN(y); + + + /* check for inf or -inf (expm1(-inf)=-1) */ + if (MPFR_IS_INF(x)) + { + if(MPFR_SIGN(x) > 0) + { + MPFR_SET_INF(y); + MPFR_SET_SAME_SIGN(y,x); + return 0; + } + else + return mpfr_set_ui(y,-1,rnd_mode); + } + + MPFR_CLEAR_INF(y); + + + if(!MPFR_NOTZERO(x)) + { + MPFR_SET_ZERO(y); /* expm1(+/- 0) = +/- 0 */ + MPFR_SET_SAME_SIGN(y,x); + return 0; + } + + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t te,t; + + /* Declaration of the size variable */ + mp_prec_t Nx = MPFR_PREC(x); /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ + + mp_prec_t Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt=Nt+5+_mpfr_ceil_log2(Nt); + + /* initialise of intermediary variable */ + mpfr_init(t); + mpfr_init(te); + + /* First computation of cosh */ + do { + + /* reactualisation of the precision */ + mpfr_set_prec(t,Nt); + mpfr_set_prec(te,Nt); + + /* compute expm1 */ + mpfr_exp(te,x,GMP_RNDN); /* exp(x)*/ + mpfr_sub_ui(t,te,1,GMP_RNDN); /* exp(x)-1 */ + + /* estimation of the error */ + /*err=Nt-(_mpfr_ceil_log2(1+pow(2,MPFR_EXP(te)-MPFR_EXP(t))));*/ + err=Nt-(MAX(MPFR_EXP(te)-MPFR_EXP(t),0)+1); + + /* actualisation of the precision */ + Nt += 10; + + } while ((err <0) || !mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny)); + + inexact = mpfr_set(y,t,rnd_mode); + + mpfr_clear(t); + mpfr_clear(te); + } + return inexact; +} diff --git a/mpfr/extract.c b/mpfr/extract.c index ccfd380b7..ee9fc3002 100644 --- a/mpfr/extract.c +++ b/mpfr/extract.c @@ -1,20 +1,20 @@ /* mpfr_extract -- bit-extraction function for the binary splitting algorithm -Copyright (C) 2000 Free Software Foundation. +Copyright (C) 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -34,14 +34,7 @@ MA 02111-1307, USA. */ - 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; diff --git a/mpfr/factorial.c b/mpfr/factorial.c new file mode 100644 index 000000000..eddabea2d --- /dev/null +++ b/mpfr/factorial.c @@ -0,0 +1,104 @@ +/* mpfr_fac_ui -- factorial of a non-negative integer + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + + /* The computation of n! is done by + + n!=prod^{n}_{i=1}i + */ + +int +mpfr_fac_ui (mpfr_ptr y, unsigned long int x , mp_rnd_t rnd_mode) +{ + + /****** Declaration ******/ + + mpfr_t t; /* Variable of Intermediary Calculation*/ + int i; + int round, inexact = 0; + int boucle = 1; + + mp_prec_t Ny; /* Precision of output variable */ + mp_prec_t Nt; /* Precision of Intermediary Calculation variable */ + mp_prec_t err; /* Precision of error */ + + /***** test x = 0 ******/ + + if (x == 0) + { + mpfr_set_ui (y, 1, GMP_RNDN); /* 0! = 1 */ + return 0; + } + else + { + /* Initialisation of the Precision */ + Ny=MPFR_PREC(y); + + Nt=Ny+2*(int)_mpfr_ceil_log2((double)x)+10; /*compute the size of intermediary variable */ + + + mpfr_init2(t, Nt);/* initialise of intermediary variable */ + + while (boucle) + { + inexact = mpfr_set_ui (t, 1, GMP_RNDZ); + + for(i=2;i<=x;i++) /* compute factorial */ + { + round = mpfr_mul_ui (t, t, i, GMP_RNDZ); + /* assume the first inexact product gives the sign + of difference: is that always correct? */ + if (inexact == 0) + inexact = round; + } + + err = Nt - 1 - (int) _mpfr_ceil_log2 ((double) Nt); + + round = !inexact || mpfr_can_round (t,err,GMP_RNDZ,rnd_mode,Ny); + + if (round) + { + round = mpfr_set (y, t, rnd_mode); + if (inexact == 0) + inexact = round; + boucle=0; + } + else + { + Nt=Nt+10; + /*initialise of intermediary variable */ + mpfr_set_prec(t, Nt); + } + } + + mpfr_clear(t); + return inexact; + + } +} + + + + diff --git a/mpfr/floor.c b/mpfr/floor.c new file mode 100644 index 000000000..7509f699b --- /dev/null +++ b/mpfr/floor.c @@ -0,0 +1,2 @@ +#define MPFR_FLOOR 1 +#include "trunc.c" diff --git a/mpfr/fma.c b/mpfr/fma.c new file mode 100644 index 000000000..0a6c1ce73 --- /dev/null +++ b/mpfr/fma.c @@ -0,0 +1,200 @@ +/* mpfr_fma -- Floating multiply-add + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser +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" + + +/* The computation of fma of x y and u is done by + fma(s,x,y,z)= z + x*y = s +*/ + +int +mpfr_fma (mpfr_ptr s, mpfr_srcptr x ,mpfr_srcptr y ,mpfr_srcptr z , mp_rnd_t rnd_mode) +{ + int inexact =0; + /* Flag calcul exacte */ + int not_exact=0; + + /* particular cases */ + if (MPFR_IS_NAN(x) || MPFR_IS_NAN(y) || MPFR_IS_NAN(z)) + { + MPFR_SET_NAN(s); + return 1; + } + + /* cases Inf*0+z, 0*Inf+z, Inf-Inf */ + if ((MPFR_IS_INF(x) && MPFR_IS_ZERO(y)) || + (MPFR_IS_INF(y) && MPFR_IS_ZERO(x)) || + ((MPFR_IS_INF(x) || MPFR_IS_INF(y)) && MPFR_IS_INF(z) && + ((MPFR_SIGN(x) * MPFR_SIGN(y)) != MPFR_SIGN(z)))) + { + MPFR_SET_NAN(s); + return 1; + } + + MPFR_CLEAR_NAN(s); + + if (MPFR_IS_INF(x) || MPFR_IS_INF(y)) + { + if (MPFR_IS_INF(z)) /* case Inf-Inf already checked above */ + { + MPFR_SET_INF(s); + MPFR_SET_SAME_SIGN(s, z); + return 0; + } + else /* z is finite */ + { + MPFR_SET_INF(s); + if (MPFR_SIGN(s) != (MPFR_SIGN(x) * MPFR_SIGN(y))) + MPFR_CHANGE_SIGN(s); + return 0; + } + } + + /* now x and y are finite */ + if (MPFR_IS_INF(z)) + { + MPFR_SET_INF(s); + MPFR_SET_SAME_SIGN(s, z); + return 0; + } + + MPFR_CLEAR_INF(s); + + if(!MPFR_NOTZERO(x) || !MPFR_NOTZERO(y)) + return mpfr_set (s, z, rnd_mode); + if (!MPFR_NOTZERO(z)) + return mpfr_mul (s, x, y, rnd_mode); + + /* General case */ + /* Detail of the compute */ + + /* u <- x*y */ + /* t <- z+u */ + { + /* Declaration of the intermediary variable */ + mpfr_t t, u; + int d,fl1,fl2; + int accu=0; + + /* Declaration of the size variable */ + mp_prec_t Nx = MPFR_PREC(x); /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ + mp_prec_t Nz = MPFR_PREC(z); /* Precision of input variable */ + mp_prec_t Ns = MPFR_PREC(s); /* Precision of output variable */ + int Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + unsigned int first_pass=0; /* temporary precision */ + + /* compute the precision of intermediary variable */ + Nt=MAX(MAX(Nx,Ny),Nz); + + /* the optimal number of bits is MPFR_EXP(u)-MPFR_EXP(v)+1 */ + /* but u and v are not yet compute, also we take in account */ + /* just one bit */ + Nt=Nt+1+_mpfr_ceil_log2(Nt)+20; + /* initialise the intermediary variables */ + mpfr_init(u); + mpfr_init(t); + + /* First computation of fma */ + do { + if(accu++ >2) + { + mpfr_clear(t); + mpfr_clear(u); + goto fma_paul; + } + + not_exact=0; + + /* reactualisation of the precision */ + mpfr_set_prec(u,Nt); + mpfr_set_prec(t,Nt); + + /* computations */ + fl1=mpfr_mul(u,x,y,GMP_RNDN); + if(fl1) not_exact=1; + + fl2=mpfr_add(t,z,u,GMP_RNDN); + if(fl2) not_exact=1; + + /*Nt=Nt+(d+1)+_mpfr_ceil_log2(Nt); */ + d = MPFR_EXP(u)-MPFR_EXP(t); + + /* estimation of the error */ + err=Nt-(d+1); + + /* actualisation of the precision */ + Nt +=(1-first_pass)*d + first_pass*10; + if(Nt<0)Nt=0; + + first_pass=1; + + } while ( (fl1!=fl2) || (err <0) || ((!mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ns)) && not_exact )); + + inexact = mpfr_set (s, t, rnd_mode); + mpfr_clear(t); + mpfr_clear(u); + + goto fin; + } + + + + fma_paul: + + + /* General case */ + /* Detail of the compute */ + /* u <- x*y exact */ + /* s <- z+u */ + { + mpfr_t u; + + /* if we take prec(u) >= prec(x) + prec(y), the product + u <- x*y is always exact */ + mpfr_init2 (u, MPFR_PREC(x) + MPFR_PREC(y)); + + mpfr_mul (u, x, y, GMP_RNDN); /* always exact */ + inexact = mpfr_add (s, z, u, rnd_mode); + mpfr_clear(u); + } + return inexact; + + fin: + if (not_exact == 0 && inexact == 0) + return 0; + + if (not_exact != 0 && inexact == 0) + return 1; + + return inexact; + +} + diff --git a/mpfr/generic.c b/mpfr/generic.c index 88e509367..b49c17ef0 100644 --- a/mpfr/generic.c +++ b/mpfr/generic.c @@ -1,20 +1,20 @@ -/* +/* generic file for evaluation of hypergeometric series using binary splitting -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999-2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -23,26 +23,16 @@ MA 02111-1307, USA. */ # 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__ +/* Compute the first 2^m terms from the hypergeometric series + with x = p / 2^r */ +static int 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; @@ -57,26 +47,33 @@ GENERIC (y, p, r, m) #endif int diff, expo; int precy = MPFR_PREC(y); + TMP_DECL(marker); + + TMP_MARK(marker); MPFR_CLEAR_FLAGS(y); n = 1 << m; - P = (mpz_t*) (*__gmp_allocate_func) ((m+1) * sizeof(mpz_t)); - S = (mpz_t*) (*__gmp_allocate_func) ((m+1) * sizeof(mpz_t)); - ptoj = (mpz_t*) (*__gmp_allocate_func) ((m+1) * sizeof(mpz_t)); /* ptoj[i] = mantissa^(2^i) */ + 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) */ #ifdef A - T = (mpz_t*) (*__gmp_allocate_func) ((m+1) * sizeof(mpz_t)); + T = (mpz_t*) TMP_ALLOC ((m+1) * sizeof(mpz_t)); #endif #ifdef R_IS_RATIONAL - qtoj = (mpz_t*) (*__gmp_allocate_func) ((m+1) * sizeof(mpz_t)); + qtoj = (mpz_t*) TMP_ALLOC ((m+1) * sizeof(mpz_t)); #endif - for (i=0;i<=m;i++) { mpz_init(P[i]); mpz_init(S[i]); mpz_init(ptoj[i]); + 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]); + mpz_init (qtoj[i]); #endif #ifdef A - mpz_init(T[i]); + mpz_init (T[i]); #endif - } - mpz_set(ptoj[0], p); + } + mpz_set (ptoj[0], p); #ifdef C # if C2 != 1 mpz_mul_ui(ptoj[0], ptoj[0], C2); @@ -184,32 +181,28 @@ GENERIC (y, p, r, m) MPFR_EXP(y) += expo; #ifdef R_IS_RATIONAL - /* division exacte */ - mpz_div_ui(qtoj[m], qtoj[m], r); - mpfr_init2(tmp, MPFR_PREC(y)); - mpfr_set_z(tmp, qtoj[m] , GMP_RNDD); - mpfr_div(y, y, tmp, GMP_RNDD); - mpfr_clear(tmp); + /* exact division */ + mpz_div_ui (qtoj[m], qtoj[m], r); + mpfr_init2 (tmp, MPFR_PREC(y)); + 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 - } - (*__gmp_free_func) (P, (m+1) * sizeof(mpz_t)); - (*__gmp_free_func) (S, (m+1) * sizeof(mpz_t)); - (*__gmp_free_func) (ptoj, (m+1) * sizeof(mpz_t)); + for (i=0;i<=m;i++) + { + mpz_clear (P[i]); + mpz_clear (S[i]); + mpz_clear (ptoj[i]); #ifdef R_IS_RATIONAL - (*__gmp_free_func) (qtoj, (m+1) * sizeof(mpz_t)); + mpz_clear (qtoj[i]); #endif #ifdef A - (*__gmp_free_func) (T, (m+1) * sizeof(mpz_t)); + mpz_clear (T[i]); #endif + } + TMP_FREE(marker); return 0; } diff --git a/mpfr/get_str.c b/mpfr/get_str.c index e692298c6..93af194b0 100644 --- a/mpfr/get_str.c +++ b/mpfr/get_str.c @@ -1,26 +1,24 @@ /* mpfr_get_str -- output a floating-point number to a string -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ -/* #define DEBUG */ - #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -38,18 +36,8 @@ MA 02111-1307, USA. */ For op = 3.1416 we get str = "31416" and expptr=1. */ char* -#if __STDC__ mpfr_get_str (char *str, mp_exp_t *expptr, int base, size_t n, mpfr_srcptr op, mp_rnd_t rnd_mode) -#else -mpfr_get_str (str, expptr, base, n, op, rnd_mode) - char *str; - mp_exp_t *expptr; - int base; - size_t n; - mpfr_srcptr op; - mp_rnd_t rnd_mode; -#endif { double d; long e, q, div, p, err, prec, sh; @@ -65,7 +53,7 @@ mpfr_get_str (str, expptr, base, n, op, rnd_mode) exit(1); } - neg = (MPFR_SIGN(op)<0) ? 1 : 0; + neg = MPFR_SIGN(op) < 0; if (MPFR_IS_INF(op)) { if (str == NULL) @@ -87,7 +75,7 @@ mpfr_get_str (str, expptr, base, n, op, rnd_mode) return str0; /* strlen(str0) = neg + n */ } - count_leading_zeros(pow2, (mp_limb_t)base); + count_leading_zeros(pow2, (mp_limb_t) base); pow2 = BITS_PER_MP_LIMB - pow2 - 1; if (base != (1<<pow2)) pow2=0; /* if pow2 <> 0, then base = 2^pow2 */ @@ -100,11 +88,18 @@ mpfr_get_str (str, expptr, base, n, op, rnd_mode) i.e. f = 1 + floor(log(|op|)/log(base)) = 1 + floor((log(|m|)+e*log(2))/log(base)) */ /* f = 1 + (int) floor((log(d)/LOG2+(double)e)*LOG2/log((double)base)); */ - d = ((double) e + (double) _mpfr_floor_log2(d)) + /* when base = 2^pow2, then |op| < 2^(pow2*f) + i.e. e <= pow2*f and f = ceil(e/pow2) */ + if (pow2) + f = ((e < 0) ? e : (e + pow2 - 1)) / pow2; + else + { + 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++; + /* 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 GMP_RNDU for example, we have: x*2^(e-p) <= y*base^(f-n) @@ -112,19 +107,13 @@ mpfr_get_str (str, expptr, base, n, op, rnd_mode) 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)) */ 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; + 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); @@ -142,10 +131,13 @@ mpfr_get_str (str, expptr, base, n, op, rnd_mode) } } - if (pow2) { - if (div) mpfr_div_2exp(b, op, pow2*p, rnd_mode); - else mpfr_mul_2exp(b, op, pow2*p, rnd_mode); - } + if (pow2) + { + if (div) + mpfr_div_2exp (b, op, pow2*p, rnd_mode); + else + mpfr_mul_2exp (b, op, pow2*p, rnd_mode); + } else { /* compute base^p with q bits and rounding towards zero */ mpfr_set_prec(b, q); @@ -158,17 +150,10 @@ 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) 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) { /* if the intermediate precision exceeds twice that of the input, a worst-case for the division cannot occur */ @@ -185,7 +170,8 @@ mpfr_get_str (str, expptr, base, n, op, rnd_mode) case GMP_RNDD: rnd_mode=GMP_RNDU; break; } - if (ok) mpfr_round(b, rnd_mode, MPFR_EXP(b)); + if (ok) + mpfr_round (b, rnd_mode, MPFR_EXP(b)); prec=MPFR_EXP(b); /* may have changed due to rounding */ diff --git a/mpfr/gmp_op.c b/mpfr/gmp_op.c new file mode 100644 index 000000000..15925c941 --- /dev/null +++ b/mpfr/gmp_op.c @@ -0,0 +1,122 @@ +/* mpfr_cos -- cosine of a floating-point number + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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_mul_z (mpfr_ptr y, mpfr_srcptr x, mpz_srcptr z,mp_rnd_t rnd_mode) +{ + mpfr_t t; + int res; + mpfr_init(t); + mpfr_set_z(t,z,rnd_mode); + res=mpfr_mul(y,x,t,rnd_mode); + mpfr_clear(t); + return(res); +} + +int +mpfr_div_z (mpfr_ptr y, mpfr_srcptr x, mpz_srcptr z, mp_rnd_t rnd_mode) +{ + mpfr_t t; + int res; + mpfr_init(t); + mpfr_set_z(t,z,rnd_mode); + res=mpfr_div(y,x,t,rnd_mode); + mpfr_clear(t); + return(res); +} + +int +mpfr_add_z (mpfr_ptr y, mpfr_srcptr x, mpz_srcptr z, mp_rnd_t rnd_mode) +{ + mpfr_t t; + int res; + mpfr_init(t); + mpfr_set_z(t,z,rnd_mode); + res=mpfr_add(y,x,t,rnd_mode); + mpfr_clear(t); + return(res); +} + +int +mpfr_sub_z (mpfr_ptr y, mpfr_srcptr x, mpz_srcptr z,mp_rnd_t rnd_mode) +{ + mpfr_t t; + int res; + mpfr_init(t); + mpfr_set_z(t,z,rnd_mode); + res=mpfr_sub(y,x,t,rnd_mode); + mpfr_clear(t); + return(res); +} + +int +mpfr_mul_q (mpfr_ptr y, mpfr_srcptr x, mpq_srcptr z,mp_rnd_t rnd_mode) +{ + mpfr_t t; + int res; + mpfr_init(t); + mpfr_set_q(t,z,rnd_mode); + res=mpfr_mul(y,x,t,rnd_mode); + mpfr_clear(t); + return(res); +} + +int +mpfr_div_q (mpfr_ptr y, mpfr_srcptr x, mpq_srcptr z, mp_rnd_t rnd_mode) +{ + mpfr_t t; + int res; + mpfr_init(t); + mpfr_set_q(t,z,rnd_mode); + res=mpfr_div(y,x,t,rnd_mode); + mpfr_clear(t); + return(res); +} + +int +mpfr_add_q (mpfr_ptr y, mpfr_srcptr x, mpq_srcptr z, mp_rnd_t rnd_mode) +{ + mpfr_t t; + int res; + mpfr_init(t); + mpfr_set_q(t,z,rnd_mode); + res=mpfr_add(y,x,t,rnd_mode); + mpfr_clear(t); + return(res); +} + +int +mpfr_sub_q (mpfr_ptr y, mpfr_srcptr x, mpq_srcptr z,mp_rnd_t rnd_mode) +{ + mpfr_t t; + int res; + mpfr_init(t); + mpfr_set_q(t,z,rnd_mode); + res=mpfr_sub(y,x,t,rnd_mode); + mpfr_clear(t); + return(res); +} diff --git a/mpfr/hypot.c b/mpfr/hypot.c new file mode 100644 index 000000000..1e799f9a9 --- /dev/null +++ b/mpfr/hypot.c @@ -0,0 +1,134 @@ +/* mpfr_hypot -- Euclidean distance + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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" + + /* The computation of hypot of x and y is done by + + hypot(x,y)= sqrt(x^2+y^2) = z + */ + +int +mpfr_hypot (mpfr_ptr z, mpfr_srcptr x ,mpfr_srcptr y , mp_rnd_t rnd_mode) +{ + int inexact; + /* Flag calcul exacte */ + int not_exact=0; + + /* particular cases */ + + if (MPFR_IS_NAN(x) || MPFR_IS_NAN(y)) + { + MPFR_SET_NAN(z); + return 1; + } + + MPFR_CLEAR_NAN(z); + + if (MPFR_IS_INF(x) || MPFR_IS_INF(y)) + { + MPFR_SET_INF(z); + if (MPFR_SIGN(z) < 0) + MPFR_CHANGE_SIGN(z); + return 0; + } + + MPFR_CLEAR_INF(z); + + if(!MPFR_NOTZERO(x)) + return mpfr_abs (z, y, rnd_mode); + + if(!MPFR_NOTZERO(y)) + return mpfr_abs (z, x, rnd_mode); + + /* General case */ + + { + /* Declaration of the intermediary variable */ + mpfr_t t, te,ti; + /* Declaration of the size variable */ + mp_prec_t Nx = MPFR_PREC(x); /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ + mp_prec_t Nz = MPFR_PREC(z); /* Precision of input variable */ + + int Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(MAX(Nx,Ny),Nz); + + /* compute the size of intermediary variable -- see algorithms.ps */ + Nt=Nt+2+_mpfr_ceil_log2(Nt); + + /* initialise the intermediary variables */ + mpfr_init(t); + mpfr_init(te); + mpfr_init(ti); + + /* Hypot */ + do { + not_exact=0; + /* reactualisation of the precision */ + mpfr_set_prec(t,Nt); + mpfr_set_prec(te,Nt); + mpfr_set_prec(ti,Nt); + + /* computations of hypot */ + if(mpfr_mul(te,x,x,GMP_RNDN)) /* x^2 */ + not_exact=1; + + if(mpfr_mul(ti,y,y,GMP_RNDN)) /* y^2 */ + not_exact=1; + + if(mpfr_add(t,te,ti,GMP_RNDD)) /*x^2+y^2*/ + not_exact=1; + + if(mpfr_sqrt(t,t,GMP_RNDN)) /* sqrt(x^2+y^2)*/ + not_exact=1; + + /* estimation of the error */ + err=Nt-(2); + + Nt += 10; + if(Nt<0)Nt=0; + + } while ((err <0) || ((!mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Nz)) && not_exact)); + + inexact = mpfr_set (z, t, rnd_mode); + mpfr_clear(t); + mpfr_clear(ti); + mpfr_clear(te); + + } + + if (not_exact == 0 && inexact == 0) + return 0; + + if (not_exact != 0 && inexact == 0) + return 1; + + return inexact; +} diff --git a/mpfr/init.c b/mpfr/init.c index d2474aa78..44f6eeae4 100644 --- a/mpfr/init.c +++ b/mpfr/init.c @@ -1,62 +1,31 @@ /* mpfr_init -- initialize a floating-point number -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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_init2 (mpfr_ptr x, mp_prec_t p) -#else -mpfr_init2 (x, p) - mpfr_ptr x; - mp_prec_t p; -#endif -{ - mp_prec_t xsize; - - if (p==0) { - fprintf(stderr, "*** cannot initialize mpfr with precision 0\n"); exit(1); - } - - xsize = (p - 1)/BITS_PER_MP_LIMB + 1; - - MPFR_PREC(x) = p; - MPFR_MANT(x) = (mp_ptr) (*__gmp_allocate_func) (xsize * BYTES_PER_MP_LIMB); - 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, __mpfr_default_fp_bit_precision); + mpfr_init2 (x, __mpfr_default_fp_bit_precision); } diff --git a/mpfr/init2.c b/mpfr/init2.c new file mode 100644 index 000000000..6261ae305 --- /dev/null +++ b/mpfr/init2.c @@ -0,0 +1,46 @@ +/* mpfr_init2 -- initialize a floating-point number with given precision + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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" + +void +mpfr_init2 (mpfr_ptr x, mp_prec_t p) +{ + mp_prec_t xsize; + + if (p==0) { + fprintf(stderr, "*** cannot initialize mpfr with precision 0\n"); exit(1); + } + + xsize = (p - 1)/BITS_PER_MP_LIMB + 1; + + MPFR_PREC(x) = p; + MPFR_MANT(x) = (mp_ptr) (*__gmp_allocate_func) (xsize * BYTES_PER_MP_LIMB); + 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 */ +} diff --git a/mpfr/inp_str.c b/mpfr/inp_str.c index 422e5f797..a218f8c3c 100644 --- a/mpfr/inp_str.c +++ b/mpfr/inp_str.c @@ -1,21 +1,22 @@ /* 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. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. +(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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -28,15 +29,7 @@ MA 02111-1307, USA. */ #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; @@ -85,9 +78,10 @@ mpfr_inp_str (rop, stream, base, rnd_mode) str[str_size] = 0; retval = mpfr_set_str (rop, str, base, rnd_mode); + (*__gmp_free_func) (str, alloc_size); + if (retval == -1) return 0; /* error */ - (*__gmp_free_func) (str, alloc_size); return str_size + nread; } diff --git a/mpfr/isinf.c b/mpfr/isinf.c new file mode 100644 index 000000000..04d86edfc --- /dev/null +++ b/mpfr/isinf.c @@ -0,0 +1,31 @@ +/* mpfr_inf_p -- check for infinities + +Copyright (C) 2000-2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +int +mpfr_inf_p (mpfr_srcptr x) +{ + return !MPFR_IS_NAN(x) && MPFR_IS_INF(x); +} diff --git a/mpfr/isinteger.c b/mpfr/isinteger.c new file mode 100644 index 000000000..0efc5ac09 --- /dev/null +++ b/mpfr/isinteger.c @@ -0,0 +1,49 @@ +/* mpfr_isinteger -- test if a mpfr variable is integer + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +int +mpfr_isinteger (mpfr_srcptr x) +{ + + mpfr_t u; + int expo; + mp_prec_t prec; + + expo=(int)MPFR_EXP(x); + prec=MPFR_PREC(x); + + if (expo<=0) + return 0; + + if (expo>=prec) + return 1; + + mpfr_init2(u,prec); + mpfr_trunc(u,x); + + if(mpfr_cmp(x,u)==0) return 1; + else return 0; +} diff --git a/mpfr/isnan.c b/mpfr/isnan.c index f76b7c86a..acd3d3dd7 100644 --- a/mpfr/isnan.c +++ b/mpfr/isnan.c @@ -1,20 +1,20 @@ -/* mpfr_nan_p, mpfr_inf_p -- check for NaN or infinities +/* mpfr_nan_p -- check for NaN Copyright (C) 2000-2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -29,15 +29,3 @@ mpfr_nan_p (mpfr_srcptr x) { return MPFR_IS_NAN (x); } - -int -mpfr_inf_p (mpfr_srcptr x) -{ - return (!MPFR_IS_NAN(x) && MPFR_IS_INF(x)); -} - -int -mpfr_number_p (mpfr_srcptr x) -{ - return !MPFR_IS_NAN(x) && !MPFR_IS_INF(x); -} diff --git a/mpfr/isnum.c b/mpfr/isnum.c new file mode 100644 index 000000000..cedfab3ac --- /dev/null +++ b/mpfr/isnum.c @@ -0,0 +1,31 @@ +/* mpfr_number_p -- check for ordinary numbers + +Copyright (C) 2000-2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +int +mpfr_number_p (mpfr_srcptr x) +{ + return !MPFR_IS_NAN(x) && !MPFR_IS_INF(x); +} diff --git a/mpfr/log.c b/mpfr/log.c index 726a7bd5b..e15eb0f31 100644 --- a/mpfr/log.c +++ b/mpfr/log.c @@ -1,20 +1,20 @@ /* mpfr_log -- natural logarithm of a floating-point number -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -42,16 +42,9 @@ MA 02111-1307, USA. */ /* #define DEBUG */ int -#if __STDC__ mpfr_log (mpfr_ptr r, mpfr_srcptr a, mp_rnd_t rnd_mode) -#else -mpfr_log (r, a, rnd_mode) - mpfr_ptr r; - mpfr_srcptr a; - mp_rnd_t rnd_mode; -#endif { - int m, bool, size, cancel; + int m, bool, size, cancel, inexact = 0; mp_prec_t p, q; mpfr_t cst, rapport, agm, tmp1, tmp2, s, mm; mp_limb_t *cstp, *rapportp, *agmp, *tmp1p, *tmp2p, *sp, *mmp; @@ -59,36 +52,55 @@ mpfr_log (r, a, rnd_mode) TMP_DECL(marker); /* If a is NaN, the result is NaN */ - if (MPFR_IS_NAN(a)) { - MPFR_SET_NAN(r); - return 1; - } + if (MPFR_IS_NAN(a)) + { + MPFR_SET_NAN(r); + return 1; /* NaN is inexact */ + } 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_SIGN(a) < 0) /* log(-Inf) = NaN */ + { + MPFR_SET_NAN(r); + return 1; + } + else /* log(+Inf) = +Inf */ + { + MPFR_SET_INF(r); + if (MPFR_SIGN(r) < 0) + MPFR_CHANGE_SIGN(r); + return 0; + } } + /* Now we can clear the flags without damage even if r == a */ + MPFR_CLEAR_INF(r); + if (MPFR_IS_ZERO(a)) { MPFR_SET_INF(r); - if (MPFR_SIGN(r) < 0) MPFR_CHANGE_SIGN(r); - return 1; + if (MPFR_SIGN(r) > 0) + MPFR_CHANGE_SIGN(r); + return 0; /* log(0) is an exact infinity */ } - /* Now we can clear the flags without damage even if r == a */ - MPFR_CLEAR_INF(r); + /* If a is negative, the result is NaN */ + if (MPFR_SIGN(a) < 0) + { + MPFR_SET_NAN(r); + return 1; + } /* If a is 1, the result is 0 */ - if (mpfr_cmp_ui_2exp(a,1,0)==0){ - MPFR_SET_ZERO(r); - return 0; /* only case where the result is exact */ - } + if (mpfr_cmp_ui_2exp (a, 1, 0) == 0) + { + MPFR_SET_ZERO(r); + return 0; /* only "normal" case where the result is exact */ + } q=MPFR_PREC(r); @@ -149,7 +161,7 @@ mpfr_log (r, a, rnd_mode) 4 ulps from the 4/s^2 second order term, plus the cancelled bits */ if (mpfr_can_round (cst, p - cancel - 4, GMP_RNDN, rnd_mode, q) == 1) { - mpfr_set (r, cst, rnd_mode); + inexact = mpfr_set (r, cst, rnd_mode); #ifdef DEBUG printf("result="); mpfr_print_raw(r); putchar('\n'); #endif @@ -164,7 +176,7 @@ mpfr_log (r, a, rnd_mode) TMP_FREE(marker); } - return 1; /* result is inexact */ + return inexact; /* result is inexact */ } diff --git a/mpfr/log1p.c b/mpfr/log1p.c new file mode 100644 index 000000000..3eb4d110e --- /dev/null +++ b/mpfr/log1p.c @@ -0,0 +1,134 @@ +/* mpfr_log1p -- Compute log(1+x) + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + + /* The computation of log1p is done by + + log1p(x)=log(1+x) + */ + +int +mpfr_log1p (mpfr_ptr y, mpfr_srcptr x , mp_rnd_t rnd_mode) +{ + int comp, inexact = 0; + + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(y); + return 1; + } + MPFR_CLEAR_NAN(y); + + /* check for inf or -inf (result is not defined) */ + if (MPFR_IS_INF(x)) + { + if(MPFR_SIGN(x) > 0) + { + MPFR_SET_INF(y); + + if (MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN(y); + + return 0; + } + else + { + MPFR_SET_NAN(y); + return 1; + } + } + + comp = mpfr_cmp_si(x,-1); + /* x<-1 undefined */ + if(comp < 0) + { + MPFR_SET_NAN(y); + return 1; + } + /* x=0: log1p(-1)=-inf (division by zero) */ + if(comp == 0) + { + DIVIDE_BY_ZERO; /* Exception GMP */ + MPFR_SET_INF(y); + if (MPFR_SIGN(y) > 0) + MPFR_CHANGE_SIGN(y); + return 1; + } + + MPFR_CLEAR_INF(y); + + if(!MPFR_NOTZERO(x)) + { + MPFR_SET_ZERO(y); /* log1p(+/- 0) = +/- 0 */ + MPFR_SET_SAME_SIGN(y, x); + return 0; + } + + + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t t; + + /* Declaration of the size variable */ + mp_prec_t Nx = MPFR_PREC(x); /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ + + mp_prec_t Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt=Nt+5+_mpfr_ceil_log2(Nt); + + /* initialise of intermediary variable */ + mpfr_init(t); + + /* First computation of cosh */ + do { + + /* reactualisation of the precision */ + mpfr_set_prec(t, Nt); + + /* compute log1p */ + mpfr_add_ui (t, x, 1, GMP_RNDN); /* 1+x */ + mpfr_log (t, t, GMP_RNDN); /* log(1+x)*/ + + /* estimation of the error */ + /*err=Nt-(_mpfr_ceil_log2(1+pow(2,1-MPFR_EXP(t))));*/ + err=Nt-(MAX(1-MPFR_EXP(t),0)+1); + + /* actualisation of the precision */ + Nt += 10; + + } while ((err<0) || !mpfr_can_round(t, err, GMP_RNDN, rnd_mode, Ny)); + + inexact = mpfr_set (y, t, rnd_mode); + + mpfr_clear(t); + } + return inexact; +} diff --git a/mpfr/log2.c b/mpfr/log2.c index 70f4aabd0..fcfc76920 100644 --- a/mpfr/log2.c +++ b/mpfr/log2.c @@ -1,37 +1,37 @@ /* mpfr_const_log2 -- compute natural logarithm of 2 -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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 "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 _PROTO ((mpfr_ptr, mpz_srcptr, int, int)); -int mpfr_const_aux_log2 _PROTO ((mpfr_ptr, mp_rnd_t)); +static int mpfr_aux_log2 _PROTO ((mpfr_ptr, mpz_srcptr, int, int)); +static int mpfr_const_aux_log2 _PROTO ((mpfr_ptr, mp_rnd_t)); #define A #define A1 1 @@ -53,14 +53,8 @@ int mpfr_const_aux_log2 _PROTO ((mpfr_ptr, mp_rnd_t)); #undef C1 #undef C2 -int -#if __STDC__ +static int 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; @@ -112,6 +106,11 @@ mpfr_const_aux_log2 (mylog, rnd_mode) return 0; } +/* Cross-over point from nai"ve Taylor series to binary splitting, + obtained experimentally on a Pentium II. Optimal value for + target machine should be determined by tuneup. */ +#define LOG2_THRESHOLD 25000 + /* 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) @@ -126,11 +125,7 @@ mpfr_const_aux_log2 (mylog, rnd_mode) Then 2^N*log(2)-S'(N) <= N-1+2/N <= N for N>=2. */ void -#if __STDC__ mpfr_const_log2 (mpfr_ptr x, mp_rnd_t rnd_mode) -#else -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; @@ -147,38 +142,45 @@ mpfr_const_log2 (x, rnd_mode) mpfr_ptr x; mp_rnd_t rnd_mode; } /* need to recompute */ - 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 + if (precx < LOG2_THRESHOLD) /* use nai"ve Taylor series evaluation */ { - /* use binary splitting method */ - mpfr_const_aux_log2(x, rnd_mode); + 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; + 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/log_base_10.c b/mpfr/log_base_10.c new file mode 100644 index 000000000..b1e5e7d6f --- /dev/null +++ b/mpfr/log_base_10.c @@ -0,0 +1,147 @@ +/* mpfr_log10 -- log in base 10 + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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" + + /* The computation of r=log10(a) + + r=log10(a)=log(a)/log(10) + */ + +int +mpfr_log10 (mpfr_ptr r, mpfr_srcptr a , mp_rnd_t rnd_mode) +{ + + int inexact = 0; + + /* If a is NaN, the result is NaN */ + if (MPFR_IS_NAN(a)) + { + MPFR_SET_NAN(r); + MPFR_RET_NAN; + } + + /* If a is negative, the result is NaN */ + if (MPFR_SIGN(a) < 0) + { + if (!MPFR_IS_INF(a) && MPFR_IS_ZERO(a)) + { + MPFR_CLEAR_NAN(r); + MPFR_SET_INF(r); + if (MPFR_SIGN(r) > 0) + MPFR_CHANGE_SIGN(r); + return 0; + } + else + { + MPFR_SET_NAN(r); + MPFR_RET_NAN; + } + } + + MPFR_CLEAR_NAN(r); + + /* check for infinity before zero */ + if (MPFR_IS_INF(a)) + { + /* only +Inf can go here */ + MPFR_SET_INF(r); + if(MPFR_SIGN(r) < 0) + MPFR_CHANGE_SIGN(r); + return 0; + } + + /* Now we can clear the flags without damage even if r == a */ + + MPFR_CLEAR_INF(r); + + if (MPFR_IS_ZERO(a)) + { + MPFR_SET_INF(r); + if (MPFR_SIGN(r) > 0) + MPFR_CHANGE_SIGN(r); + /* Execption GMP*/ + return 0; + } + + /* If a is 1, the result is 0 */ + if (mpfr_cmp_ui(a,1) == 0) + { + MPFR_SET_SAME_SIGN(r,a); + MPFR_SET_ZERO(r); + return 0; + } + + + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t t, tt; + + /* Declaration of the size variable */ + mp_prec_t Nx = MPFR_PREC(a); /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(r); /* Precision of input variable */ + + mp_prec_t Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt=Nt+4+_mpfr_ceil_log2(Nt); + + /* initialise of intermediary variable */ + mpfr_init(t); + mpfr_init(tt); + + + /* First computation of log10 */ + do { + + /* reactualisation of the precision */ + mpfr_set_prec(t,Nt); + mpfr_set_prec(tt,Nt); + + /* compute log10 */ + mpfr_set_ui(t,10,GMP_RNDN); /* 10 */ + mpfr_log(t,t,GMP_RNDD); /* log(10) */ + mpfr_log(tt,a,GMP_RNDN); /* log(a) */ + mpfr_div(t,tt,t,GMP_RNDN); /* log(a)/log(10) */ + + + /* estimation of the error */ + err=Nt-4; + + /* actualisation of the precision */ + Nt += 10; + } while ((err<0) || !mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny)); + + inexact = mpfr_set(r,t,rnd_mode); + + mpfr_clear(t); + mpfr_clear(tt); + } + return inexact; +} diff --git a/mpfr/log_base_2.c b/mpfr/log_base_2.c new file mode 100644 index 000000000..234249e16 --- /dev/null +++ b/mpfr/log_base_2.c @@ -0,0 +1,151 @@ +/* mpfr_log2 -- log base 2 + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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" + + /* The computation of r=log2(a) + + r=log2(a)=log(a)/log(2) + */ + +int +mpfr_log2 (mpfr_ptr r, mpfr_srcptr a , mp_rnd_t rnd_mode) +{ + + int inexact = 0; + + /* If a is NaN, the result is NaN */ + if (MPFR_IS_NAN(a)) + { + MPFR_SET_NAN(r); + MPFR_RET_NAN; + } + + MPFR_CLEAR_NAN(r); + + /* If a is negative, the result is NaN */ + if (MPFR_SIGN(a) < 0) + { + if (!MPFR_IS_INF(a) && MPFR_IS_ZERO(a)) + { + MPFR_SET_INF(r); + if (MPFR_SIGN(r) > 0) + MPFR_CHANGE_SIGN(r); + return 0; + } + else + { + MPFR_SET_NAN(r); + MPFR_RET_NAN; + } + } + + /* check for infinity before zero */ + if (MPFR_IS_INF(a)) + { + MPFR_SET_INF(r); + if(MPFR_SIGN(r) < 0) + MPFR_CHANGE_SIGN(r); + return 0; + } + + /* Now we can clear the flags without damage even if r == a */ + + MPFR_CLEAR_INF(r); + + if (MPFR_IS_ZERO(a)) + { + MPFR_CLEAR_FLAGS(r); + MPFR_SET_INF(r); + if (MPFR_SIGN(r) > 0) + MPFR_CHANGE_SIGN(r); + /* Execption GMP*/ + return 0; + } + + /* If a is 1, the result is 0 */ + if (mpfr_cmp_ui(a,1) == 0) + { + MPFR_CLEAR_FLAGS(r); + MPFR_SET_SAME_SIGN(r,a); + MPFR_SET_ZERO(r); + return 0; + } + + /* If a is integer, log2(a) is exact*/ + if (mpfr_cmp_ui_2exp(a,1,MPFR_EXP(a)-1) == 0) + return mpfr_set_si(r,MPFR_EXP(a)-1,rnd_mode); + + + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t t, tt; + + /* Declaration of the size variable */ + mp_prec_t Nx = MPFR_PREC(a); /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(r); /* Precision of input variable */ + + mp_prec_t Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt=Nt+3+_mpfr_ceil_log2(Nt); + + /* initialise of intermediary variable */ + mpfr_init(t); + mpfr_init(tt); + + + /* First computation of log2 */ + do { + + /* reactualisation of the precision */ + mpfr_set_prec(t,Nt); + mpfr_set_prec(tt,Nt); + + /* compute log2 */ + mpfr_const_log2(t,GMP_RNDD); /* log(2) */ + mpfr_log(tt,a,GMP_RNDN); /* log(a) */ + mpfr_div(t,tt,t,GMP_RNDN); /* log(a)/log(2) */ + + + /* estimation of the error */ + err=Nt-3; + + /* actualisation of the precision */ + Nt += 10; + } while ((err<0) || !mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny)); + + inexact = mpfr_set(r,t,rnd_mode); + + mpfr_clear(t); + mpfr_clear(tt); + } + return inexact; +} diff --git a/mpfr/minmax.c b/mpfr/minmax.c new file mode 100644 index 000000000..0cb986ceb --- /dev/null +++ b/mpfr/minmax.c @@ -0,0 +1,81 @@ +/* mpfr_min -- min and max of x, y + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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" + + /* The computation of z=min(x,y) + + z=x if x <= y + z=y if x > y + */ + +int +mpfr_min (mpfr_ptr z, mpfr_srcptr x ,mpfr_srcptr y ,mp_rnd_t rnd_mode) +{ + if (MPFR_IS_NAN(x) && MPFR_IS_NAN(y) ) + { + MPFR_SET_NAN(z); + return 1; + } + MPFR_CLEAR_NAN(z); + if (MPFR_IS_NAN(x) ) + return mpfr_set(z,y,rnd_mode); + + if (MPFR_IS_NAN(y) ) + return mpfr_set(z,x,rnd_mode); + + if(mpfr_cmp(x,y) <= 0) + return mpfr_set(z,x,rnd_mode); + else + return mpfr_set(z,y,rnd_mode); +} + /* The computation of z=max(x,y) + + z=x if x >= y + z=y if x < y + */ +int +mpfr_max (mpfr_ptr z, mpfr_srcptr x ,mpfr_srcptr y ,mp_rnd_t rnd_mode) +{ + if (MPFR_IS_NAN(x) && MPFR_IS_NAN(y) ) + { + MPFR_SET_NAN(z); + return 1; + } + MPFR_CLEAR_NAN(z); + + if (MPFR_IS_NAN(x) ) + return mpfr_set(z,y,rnd_mode); + + if (MPFR_IS_NAN(y) ) + return mpfr_set(z,x,rnd_mode); + + if(mpfr_cmp(x,y) <= 0) + return mpfr_set(z,y,rnd_mode); + else + return mpfr_set(z,x,rnd_mode); +} + + diff --git a/mpfr/mpz_set_fr.c b/mpfr/mpz_set_fr.c index 007bf0e9e..38643a336 100644 --- a/mpfr/mpz_set_fr.c +++ b/mpfr/mpz_set_fr.c @@ -1,24 +1,25 @@ /* mpz_set_fr -- set a multiple-precision integer from a floating-point number -Copyright (C) 2000 Free Software Foundation. +Copyright (C) 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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 "mpfr.h" #include "mpfr-impl.h" @@ -28,28 +29,29 @@ MA 02111-1307, USA. */ /* 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 ? */ + if (MPFR_IS_NAN(f) || MPFR_IS_INF(f)) + { + fprintf (stderr, "Error in mpz_set_fr: input is NaN or Inf\n"); + exit (1); + } - fn = 1 + (MPFR_PREC(f)-1)/BITS_PER_MP_LIMB; + fn = 1 + (MPFR_PREC(f) - 1) / BITS_PER_MP_LIMB; /* check whether allocated space for z is enough */ - if (ALLOC(z) < fn) MPZ_REALLOC(z,fn); + if (ALLOC(z) < fn) + MPZ_REALLOC(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); + 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); + return MPFR_EXP(f) - MPFR_PREC(f); } diff --git a/mpfr/mul.c b/mpfr/mul.c index 945bd35ec..9165f0430 100644 --- a/mpfr/mul.c +++ b/mpfr/mul.c @@ -1,20 +1,20 @@ /* mpfr_mul -- multiply two floating-point numbers -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -25,79 +25,99 @@ MA 02111-1307, USA. */ #include "mpfr.h" #include "mpfr-impl.h" -/* Remains to do: -- 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, mp_rnd_t rnd_mode) -#else -mpfr_mul(a, b, c, rnd_mode) - mpfr_ptr a; - mpfr_srcptr b; - mpfr_srcptr c; - mp_rnd_t rnd_mode; -#endif +int +mpfr_mul (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mp_rnd_t rnd_mode) { - unsigned int bn, cn, an, tn, k; int cc; + unsigned int bn, cn, an, tn, k; + int cc, inexact = 0; mp_limb_t *ap=MPFR_MANT(a), *bp=MPFR_MANT(b), *cp=MPFR_MANT(c), *tmp, b1; long int sign_product; + mp_prec_t prec_a=MPFR_PREC(a), prec_b=MPFR_PREC(b), prec_c=MPFR_PREC(c); TMP_DECL(marker); /* deal with NaN and zero */ - 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_NAN(b) || MPFR_IS_NAN(c)) { - 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; + MPFR_CLEAR_FLAGS(a); + MPFR_SET_NAN(a); + return 1; + } + + if (MPFR_IS_INF(b)) + { + if (!MPFR_NOTZERO(c)) + { + MPFR_CLEAR_FLAGS(a); + MPFR_SET_NAN(a); + return 1; + } + else + { + if (MPFR_SIGN(a) != MPFR_SIGN(b) * MPFR_SIGN(c)) + MPFR_CHANGE_SIGN(a); + MPFR_CLEAR_FLAGS(a); + MPFR_SET_INF(a); + return 0; } } - else if (MPFR_IS_INF(c)) + 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; + if (!MPFR_NOTZERO(b)) + { + MPFR_CLEAR_FLAGS(a); + MPFR_SET_NAN(a); + return 1; + } + else + { + if (MPFR_SIGN(a) != MPFR_SIGN(b) * MPFR_SIGN(c)) + MPFR_CHANGE_SIGN(a); + MPFR_CLEAR_FLAGS(a); + MPFR_SET_INF(a); + return 0; } } - if (!MPFR_NOTZERO(b) || !MPFR_NOTZERO(c)) - { MPFR_CLEAR_FLAGS(a); MPFR_SET_ZERO(a); return; } + if (!MPFR_NOTZERO(b) || !MPFR_NOTZERO(c)) + { + MPFR_CLEAR_FLAGS(a); + MPFR_SET_ZERO(a); + return 0; + } 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 */ + MPFR_CLEAR_FLAGS(a); + an = (prec_a - 1)/BITS_PER_MP_LIMB + 1; /* nb of significant limbs of a */ + bn = (prec_b - 1)/BITS_PER_MP_LIMB + 1; /* nb of significant limbs of b */ + cn = (prec_c - 1)/BITS_PER_MP_LIMB + 1; /* nb of significant limbs of c */ + tn = (prec_c + prec_b - 1)/BITS_PER_MP_LIMB + 1; + k = bn + cn; /* effective nb of limbs used by b*c (=tn or tn+1) */ TMP_MARK(marker); - tmp = (mp_limb_t*) TMP_ALLOC(k*BYTES_PER_MP_LIMB); + tmp = (mp_limb_t*) TMP_ALLOC(k * BYTES_PER_MP_LIMB); /* multiplies two mantissa in temporary allocated space */ - b1 = (bn>=cn) ? mpn_mul(tmp, bp, bn, cp, cn) : mpn_mul(tmp, cp, cn, bp, bn); + 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^(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, - 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); - } + b1 >>= BITS_PER_MP_LIMB - 1; /* msb from the product */ + + tmp += k - tn; + if (b1 == 0) + mpn_lshift (tmp, tmp, tn, 1); + cc = mpfr_round_raw (ap, tmp, prec_b + prec_c, sign_product < 0, prec_a, + rnd_mode, &inexact); + if (cc) /* cc = 1 ==> result is a power of two */ + ap[an-1] = MP_LIMB_T_HIGHBIT; + + TMP_FREE(marker); + 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; + + if (sign_product * MPFR_SIGN(a) < 0) + MPFR_CHANGE_SIGN(a); + + return inexact; } diff --git a/mpfr/mul_2exp.c b/mpfr/mul_2exp.c index e1d030751..e070896a3 100644 --- a/mpfr/mul_2exp.c +++ b/mpfr/mul_2exp.c @@ -1,20 +1,20 @@ /* mpfr_mul_2exp -- multiply a floating-point number by a power of two -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -25,20 +25,15 @@ MA 02111-1307, USA. */ #include "mpfr.h" #include "mpfr-impl.h" -void -#if __STDC__ -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; - mp_rnd_t rnd_mode; -#endif +int +mpfr_mul_2exp (mpfr_ptr y, mpfr_srcptr x, unsigned long int n, mp_rnd_t rnd_mode) { + int inexact = 0; + /* Important particular case */ - if (y != x) mpfr_set(y, x, rnd_mode); - MPFR_EXP(y) += n; - return; + if (y != x) + inexact = mpfr_set (y, x, rnd_mode); + return ((MPFR_EXP(y) += n) > __mpfr_emax) + ? mpfr_set_overflow (y, rnd_mode, MPFR_SIGN(y)) : inexact; } diff --git a/mpfr/mul_ui.c b/mpfr/mul_ui.c index e92a79155..c997c41d9 100644 --- a/mpfr/mul_ui.c +++ b/mpfr/mul_ui.c @@ -1,20 +1,20 @@ /* mpfr_mul_ui -- multiply a floating-point number by a machine integer -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -26,26 +26,19 @@ MA 02111-1307, USA. */ #include "mpfr.h" #include "mpfr-impl.h" -void -#if __STDC__ -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 int u; - mp_rnd_t rnd_mode; -#endif +int +mpfr_mul_ui (mpfr_ptr y, mpfr_srcptr x, unsigned long int u, mp_rnd_t rnd_mode) { - mp_limb_t carry, *my, *old_my, *my2; unsigned long c; - unsigned long xsize, ysize, cnt, dif, ex, sh; + mp_limb_t *my, *old_my; + unsigned long xn, yn, cnt, c; + int inexact; TMP_DECL(marker); if (MPFR_IS_NAN(x)) { MPFR_CLEAR_FLAGS(y); MPFR_SET_NAN(y); - return; + return 1; /* a NaN is always inexact */ } if (MPFR_IS_INF(x)) @@ -54,81 +47,68 @@ mpfr_mul_ui(y, x, u, rnd_mode) if (u) { MPFR_SET_INF(y); - if (MPFR_SIGN(y) != MPFR_SIGN(x)) { MPFR_CHANGE_SIGN(y); } - return; + if (MPFR_SIGN(y) != MPFR_SIGN(x)) + MPFR_CHANGE_SIGN(y); + return 0; /* infinity is exact */ + } + else /* 0 * infinity */ + { + MPFR_SET_NAN(y); + return 1; /* NaN is inexact */ } - else { MPFR_SET_NAN(y); return; } } - MPFR_CLEAR_FLAGS(y); + if (MPFR_IS_ZERO(x) || !u) + { + MPFR_CLEAR_FLAGS(y); + MPFR_SET_ZERO(y); + return 0; /* zero is exact */ + } + + MPFR_CLEAR_FLAGS(y); + + if (u == 1) + return mpfr_set (y, x, rnd_mode); TMP_MARK(marker); - 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; + my = MPFR_MANT(y); + yn = (MPFR_PREC(y) - 1) / BITS_PER_MP_LIMB + 1; + xn = (MPFR_PREC(x) - 1) / BITS_PER_MP_LIMB + 1; - old_my = my; + old_my = my; - if (ysize < xsize) { - my = (mp_ptr) TMP_ALLOC (xsize * BYTES_PER_MP_LIMB); - dif=0; - } - else dif=ysize-xsize; + if (yn < xn + 1) + my = (mp_ptr) TMP_ALLOC ((xn + 1) * BYTES_PER_MP_LIMB); - carry = mpn_mul_1(my+dif, MPFR_MANT(x), xsize, u); - MPN_ZERO(my, dif); + my[xn] = mpn_mul_1 (my, MPFR_MANT(x), xn, u); + + /* x * u is stored in my[xn], ..., my[0] */ - /* WARNING: count_leading_zeros is undefined for carry=0 */ - if (carry) count_leading_zeros(cnt, carry); - else cnt=BITS_PER_MP_LIMB; + /* since the case u=1 was treated above, we have u >= 2, thus + my[xn] >= 1 since x was msb-normalized */ + MPFR_ASSERTN(my[xn] != 0); + count_leading_zeros(cnt, my[xn]); + mpn_lshift (my, my, xn + 1, cnt); - /* 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; + /* now my[xn], ..., my[0] is msb-normalized too, and has at most + PREC(x) + (BITS_PER_MP_LIMB - cnt) non-zero bits */ - /* 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 (old_my, my, (xn + 1) * BITS_PER_MP_LIMB, + (MPFR_SIGN(x) < 0), MPFR_PREC(y), rnd_mode, &inexact); - c = mpfr_round_raw(my+sh, my, MPFR_PREC(x), (MPFR_SIGN(x)<0), - MPFR_PREC(y)-BITS_PER_MP_LIMB+cnt, rnd_mode); + MPFR_EXP(y) = MPFR_EXP(x) + BITS_PER_MP_LIMB - cnt; - /* If cnt = 1111111111111 and c = 1 we shall get depressed */ - 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); - my[ysize - 1] |= ((mp_limb_t) 1) << (BITS_PER_MP_LIMB - 1); - } - else + if (c) /* rounded result is 1.0000000000000000... */ { - /* Warning: mpn_rshift is undefined for shift=0 */ - if (cnt!=BITS_PER_MP_LIMB) - mpn_rshift(my, my, ysize, BITS_PER_MP_LIMB - cnt); - my[ysize - 1] |= (carry << cnt); + old_my[yn-1] = MP_LIMB_T_HIGHBIT; + MPFR_EXP(y) ++; } - MPFR_EXP(y) = ex + BITS_PER_MP_LIMB - cnt; - if (ysize < xsize) MPN_COPY(old_my, my, ysize); + /* set sign */ - if (MPFR_SIGN(y) * MPFR_SIGN(x) < 0) MPFR_CHANGE_SIGN(y); + if (MPFR_SIGN(y) * MPFR_SIGN(x) < 0) + MPFR_CHANGE_SIGN(y); + TMP_FREE(marker); + + return inexact; } diff --git a/mpfr/neg.c b/mpfr/neg.c index b67e0c9d2..1944cdab9 100644 --- a/mpfr/neg.c +++ b/mpfr/neg.c @@ -1,40 +1,37 @@ /* mpfr_neg -- change the sign of a floating-point number -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999-2001 Free Software Foundation. This file is part of the MPFR Library. +Contributed by the Spaces project (LORIA/LIP6). 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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 "mpfr.h" #include "mpfr-impl.h" -void -#if __STDC__ +int 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; - mp_rnd_t rnd_mode; -#endif { - if (a != b) mpfr_set4(a, b, rnd_mode, -MPFR_SIGN(b)); - else MPFR_CHANGE_SIGN(a); - return; + if (a != b) + return mpfr_set4 (a, b, rnd_mode, -MPFR_SIGN(b)); + else + { + MPFR_CHANGE_SIGN(a); + MPFR_RET(0); + } } diff --git a/mpfr/out_str.c b/mpfr/out_str.c index 318dc7458..0ad99983c 100644 --- a/mpfr/out_str.c +++ b/mpfr/out_str.c @@ -1,20 +1,20 @@ /* mpfr_out_str -- output a floating-point number to a stream -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -27,46 +27,60 @@ MA 02111-1307, USA. */ #include "mpfr-impl.h" size_t -#if __STDC__ mpfr_out_str (FILE *stream, int base, size_t n_digits, mpfr_srcptr op, mp_rnd_t rnd_mode) -#else -mpfr_out_str (stream, base, n_digits, op, rnd_mode) - FILE *stream; - int base; - size_t n_digits; - mpfr_srcptr op; - mp_rnd_t rnd_mode; -#endif { char *s, *s0; - size_t slen, l; + size_t l; mp_exp_t e; - if (MPFR_IS_NAN(op)) { fprintf(stream, "NaN"); return 3; } - if (!MPFR_NOTZERO(op)) { fprintf(stream, "0"); return 1; } + if (MPFR_IS_NAN(op)) + { + fprintf (stream, "NaN"); + return 3; + } + if (MPFR_IS_INF(op)) { - if (MPFR_SIGN(op) == 1) { fprintf(stream, "Inf"); return 3; } - else { fprintf(stream, "-Inf"); return 4; } + if (MPFR_SIGN(op) == 1) + { + fprintf (stream, "Inf"); + return 3; + } + else + { + fprintf (stream, "-Inf"); + return 4; + } + } + + if (!MPFR_NOTZERO(op)) + { + l = (MPFR_SIGN(op) < 0) ? fprintf (stream, "-") : 0; + fprintf(stream, "0"); + return l + 1; } + if (!MPFR_NOTZERO(op)) { fprintf(stream, "0"); return 1; } 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 */ - l = strlen(s)+1; - slen = l; - if (*s == '-') fputc(*s++, stream); + l = strlen (s) + 1; /* size of allocated block returned by mpfr_get_str */ + if (*s == '-') + fputc (*s++, stream); + + /* outputs mantissa */ + fputc (*s++, stream); e--; /* leading digit */ + fputc ('.', stream); /* decimal point */ + fputs (s, stream); /* rest of mantissa */ + (*__gmp_free_func) (s0, l); - fputc(*s++, stream); e--; /* writes leading digit */ - fputc('.', stream); /* decimal point */ - fputs(s, stream); /* rest of mantissa */ + /* outputs exponent */ if (e) { l += fprintf (stream, (base <= 10 ? "e%ld" : "@%ld"), e); } - (*__gmp_free_func)(s0, slen); return l; } @@ -1,33 +1,34 @@ /* mpfr_const_pi -- compute Pi -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999-2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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 mpfr_aux_pi _PROTO ((mpfr_ptr, mpz_srcptr, int, int)); -int mpfr_pi_machin3 _PROTO ((mpfr_ptr, mp_rnd_t)); +static int mpfr_aux_pi _PROTO ((mpfr_ptr, mpz_srcptr, int, int)); +static int mpfr_pi_machin3 _PROTO ((mpfr_ptr, mp_rnd_t)); #define A #define A1 1 @@ -42,14 +43,8 @@ int mpfr_pi_machin3 _PROTO ((mpfr_ptr, mp_rnd_t)); #include "generic.c" -int -#if __STDC__ +static int 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); @@ -158,13 +153,7 @@ 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_const_pi(mpfr_ptr x, mp_rnd_t rnd_mode) -#else -mpfr_const_pi(x, rnd_mode) - mpfr_ptr x; - mp_rnd_t rnd_mode; -#endif +mpfr_const_pi (mpfr_ptr x, mp_rnd_t rnd_mode) { int N, oldN, n, prec; mpz_t pi, num, den, d3, d2, tmp; mpfr_t y; diff --git a/mpfr/pow.c b/mpfr/pow.c index 3032c5d72..60398c340 100644 --- a/mpfr/pow.c +++ b/mpfr/pow.c @@ -1,121 +1,270 @@ -/* mpfr_pow_ui, mpfr_ui_pow_ui -- compute the power of a floating-point - number or machine integer +/* mpfr_pow -- power function x^y -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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" -/* sets x to y^n, and returns ceil(log2(max ulp error)) */ + /* The computation of y=pow(x,z) is done by + + y=exp(z*log(x))=x^z + */ + int -#if __STDC__ -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 long int n; - mp_rnd_t rnd; -#endif +mpfr_pow (mpfr_ptr z, mpfr_srcptr x ,mpfr_srcptr y , mp_rnd_t rnd_mode) { - long int i; - unsigned long m; - double err; - mpfr_t ycopy; + int inexact = 0; + + if (MPFR_IS_NAN(x) || MPFR_IS_NAN(y) ) + { + MPFR_SET_NAN(z); + return 1; + } - if (MPFR_IS_NAN(y)) { MPFR_SET_NAN(x); return 0; } + if (MPFR_IS_INF(y)) + { + mpfr_t px; + mpfr_init2(px,MPFR_PREC(x)); + mpfr_abs(px,x,GMP_RNDN); + if(MPFR_SIGN(y)>0) + { + if(MPFR_IS_INF(x)) + { + if(MPFR_SIGN(x)>0) + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_INF(z); + if(MPFR_SIGN(z) <0) + MPFR_CHANGE_SIGN(z); + mpfr_clear(px); + return 0; + } + else + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_ZERO(z); + if(MPFR_SIGN(z) <0) + MPFR_CHANGE_SIGN(z); + mpfr_clear(px); + return 0; + } + } + if(mpfr_cmp_ui(px,1) > 0) + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_INF(z); + if(MPFR_SIGN(z) <0) + MPFR_CHANGE_SIGN(z); + mpfr_clear(px); + return 0; + } + if(mpfr_cmp_ui(px,1) < 0) + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_ZERO(z); + if(MPFR_SIGN(z) <0) + MPFR_CHANGE_SIGN(z); + mpfr_clear(px); + return 0; + } + if(mpfr_cmp_ui(px,1)==0) + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_NAN(z); + mpfr_clear(px); + return 1; + } + } + else + { + if(MPFR_IS_INF(x)) + { + if(MPFR_SIGN(x)>0) + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_ZERO(z); + if(MPFR_SIGN(z) <0) + MPFR_CHANGE_SIGN(z); + mpfr_clear(px); + return 0; + } + else + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_INF(z); + if(MPFR_SIGN(z) <0) + MPFR_CHANGE_SIGN(z); + mpfr_clear(px); + return 0; + } + } + if(mpfr_cmp_ui(px,1) > 0) + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_ZERO(z); + if(MPFR_SIGN(z) <0) + MPFR_CHANGE_SIGN(z); + mpfr_clear(px); + return 0; + } + if(mpfr_cmp_ui(px,1) < 0) + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_INF(z); + if(MPFR_SIGN(z) <0) + MPFR_CHANGE_SIGN(z); + mpfr_clear(px); + return 0; + } + if(mpfr_cmp_ui(px,1)==0) + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_NAN(z); + mpfr_clear(px); + return 1; + } + } + } - MPFR_CLEAR_NAN(x); + if(MPFR_IS_ZERO(y)) + { + return mpfr_set_ui(z,1,GMP_RNDN); + } - if (MPFR_IS_INF(y)) + if(mpfr_isinteger(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; + mpz_t zi; + long int zii; + int exptol; + + mpz_init(zi); + exptol=mpz_set_fr(zi,y); + + if (exptol>0) + mpz_mul_2exp(zi, zi, exptol); + else + mpz_tdiv_q_2exp(zi, zi, (unsigned long int) (-exptol)); + + zii=mpz_get_ui(zi); + + mpz_clear(zi); + return mpfr_pow_si(z,x,zii,rnd_mode); } - - 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); - 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); err = 2.0*err+1.0; - if (n & (1<<i)) { - mpfr_mul(x, x, (x == y) ? ycopy : y, rnd); - err += 1.0; + if (MPFR_IS_INF(x)) + { + if (MPFR_SIGN(x) > 0) + { + if (MPFR_SIGN(y) >0) + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_INF(z); + if(MPFR_SIGN(z) <0) + MPFR_CHANGE_SIGN(z); + return 0; + } + else + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_ZERO(z); + if(MPFR_SIGN(z) <0) + MPFR_CHANGE_SIGN(z); + return 0; + } + } + else + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_NAN(z); + return 1; + } + } + + MPFR_CLEAR_INF(z); + if(MPFR_SIGN(x) < 0) + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_NAN(z); + return 1; } - } - - if (x == y) mpfr_clear (ycopy); - return _mpfr_ceil_log2 (err); -} + MPFR_CLEAR_NAN(z); -/* sets x to y^n, and returns ceil(log2(max ulp error)) */ + if(mpfr_cmp_ui(x,0) == 0) + { + MPFR_CLEAR_FLAGS(z); + MPFR_SET_ZERO(z); + return 0; + } + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t t, te, ti; -/* TODO: gerer l'infini en cas de debordement ? Fait mecaniquement si fait - dans mul ? */ + /* Declaration of the size variable */ + mp_prec_t Nx = MPFR_PREC(x); /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ -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 -{ - long int i; double err; + mp_prec_t Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt=Nt+5+_mpfr_ceil_log2(Nt); + + /* initialise of intermediary variable */ + mpfr_init(t); + mpfr_init(ti); + mpfr_init(te); + + do { - MPFR_CLEAR_FLAGS(x); - if (n==0) { mpfr_set_ui(x, 1, rnd); return 0; } + /* reactualisation of the precision */ + mpfr_set_prec(t,Nt); + mpfr_set_prec(ti,Nt); + mpfr_set_prec(te,Nt); - mpfr_set_ui(x, y, rnd); - err = 1.0; + /* compute exp(y*ln(x))*/ + mpfr_log(ti,x,GMP_RNDU); /* ln(n) */ + mpfr_mul(te,y,ti,GMP_RNDU); /* y*ln(n) */ + mpfr_exp(t,te,GMP_RNDN); /* exp(x*ln(n))*/ - 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); err = 2.0 * err + 1.0; - if (n & (1<<i)) { - mpfr_mul_ui(x, x, y, rnd); - err = err + 1.0; + /* estimation of the error -- see pow function in algorithms.ps*/ + err = Nt - (MPFR_EXP(te)+3); + + /* actualisation of the precision */ + Nt += 10; + + } while (err<0 || !mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny)); + inexact = mpfr_set(z,t,rnd_mode); + mpfr_clear(t); + mpfr_clear(ti); + mpfr_clear(te); } - } - return _mpfr_ceil_log2 (err); + return inexact; } + + + + + + + diff --git a/mpfr/pow_si.c b/mpfr/pow_si.c new file mode 100644 index 000000000..07cb58151 --- /dev/null +++ b/mpfr/pow_si.c @@ -0,0 +1,160 @@ +/* mpfr_pow_si -- power function x^y with y an unsigned int + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + + /* The computation of y=pow(x,z) is done by + + y=pow_ui(x,z) if z>0 + else + y=1/pow_ui(x,z) if z<0 + */ + +int +mpfr_pow_si (mpfr_ptr y, mpfr_srcptr x, long int n, mp_rnd_t rnd_mode) +{ + + if (n>0) + return mpfr_pow_ui(y,x,(unsigned long int)n,rnd_mode); + else + { + + int inexact = 0; + + n=-n; + + /* x is NaN*/ + if (MPFR_IS_NAN(x)) + { + MPFR_SET_NAN(y); + return 1; + } + MPFR_CLEAR_NAN(y); + + /* n=0 */ + if(n==0) + return mpfr_set_ui(y,1,GMP_RNDN);; + + /* case x is INF */ + if(MPFR_IS_INF(x)) + { + if(MPFR_SIGN(x)>0) /* +Inf */ + { + MPFR_SET_ZERO(y); + if(MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN(y); + return 0; + } + else + { + MPFR_SET_ZERO(y); /* -Inf */ + if(!(n%2)) /* n is odd */ + { + if(MPFR_SIGN(y) > 0) + MPFR_CHANGE_SIGN(y); + } + else /* n is not odd */ + { + if(MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN(y); + } + return 0; + } + } + + /* case x=0 */ + if(mpfr_cmp_ui(x,0) == 0) + { + if(!(n%2)) /* n is odd */ + { + MPFR_SET_INF(y); + MPFR_SET_SAME_SIGN(y,x); + DIVIDE_BY_ZERO; /* Execption GMP*/ + return 0; + } + else /* n is not odd */ + { + MPFR_SET_INF(y); + if(MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN(y); + DIVIDE_BY_ZERO; /* Execption GMP*/ + return 0; + } + } + + MPFR_CLEAR_INF(y); + + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t t, ti; + + /* Declaration of the size variable */ + mp_prec_t Nx = MPFR_PREC(x); /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ + + mp_prec_t Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt=Nt+3+_mpfr_ceil_log2(Nt); + + /* initialise of intermediary variable */ + mpfr_init(t); + mpfr_init(ti); + + do { + + /* reactualisation of the precision */ + mpfr_set_prec(t,Nt); + mpfr_set_prec(ti,Nt); + + /* compute 1/(x^n) n>0*/ + mpfr_pow_ui(ti,y,(unsigned long int)(n),GMP_RNDN); + mpfr_ui_div(t,1,ti,GMP_RNDN); + + /* estimation of the error -- see pow function in algorithms.ps*/ + err = Nt - 3; + + /* actualisation of the precision */ + Nt += 10; + + } while (err<0 || !mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny)); + + inexact = mpfr_set(y,t,rnd_mode); + mpfr_clear(t); + mpfr_clear(ti); + } + return inexact; + } +} + + + + + + + diff --git a/mpfr/pow_ui.c b/mpfr/pow_ui.c new file mode 100644 index 000000000..42a3ee3ee --- /dev/null +++ b/mpfr/pow_ui.c @@ -0,0 +1,106 @@ +/* mpfr_pow_ui-- compute the power of a floating-point + by a machine integer + +Copyright (C) 1999, 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "mpfr.h" +#include "mpfr-impl.h" + +/* sets x to y^n, and return 0 if exact, non-zero otherwise */ +int +mpfr_pow_ui (mpfr_ptr x, mpfr_srcptr y, unsigned long int n, mp_rnd_t rnd) +{ + long int i, err; + unsigned long m; + mpfr_t res; + mp_prec_t prec; + int inexact; + mp_rnd_t rnd1; + + if (MPFR_IS_NAN(y)) + { + MPFR_SET_NAN(x); + MPFR_RET_NAN; + } + + MPFR_CLEAR_NAN(x); + + if (n == 0) /* x^0 = 1 for any x */ + { + mpfr_set_ui (x, 1, rnd); + return 0; + } + + if (MPFR_IS_INF(y)) + { + /* Inf^n = Inf, (-Inf)^n = Inf for n even, -Inf for n odd */ + 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; + } + + MPFR_CLEAR_INF(x); + + mpfr_init (res); + + prec = MPFR_PREC(x); + + rnd1 = (MPFR_SIGN(y) > 0) ? GMP_RNDU : GMP_RNDD; /* away */ + + do + { + prec += 3; + for (m=n, i=0; m; i++, m>>=1, prec++); + mpfr_set_prec (res, prec); + inexact = mpfr_set (res, y, rnd1); + err = 1; + /* now 2^(i-1) <= n < 2^i */ + for (i-=2; i>=0; i--) + { + if (mpfr_mul (res, res, res, GMP_RNDU)) + inexact = 1; + err++; + if (n & (1 << i)) + if (mpfr_mul (res, res, y, rnd1)) + inexact = 1; + } + err = prec - err; + if (err < 0) + err = 0; + } + while (inexact && (mpfr_can_round (res, err, + (MPFR_SIGN(res) > 0) ? GMP_RNDU : GMP_RNDD, rnd, MPFR_PREC(x)) == 0)); + + if (mpfr_set (x, res, rnd)) + inexact = 1; + + mpfr_clear (res); + + return inexact; +} + diff --git a/mpfr/print_raw.c b/mpfr/print_raw.c index 3b75e8eb3..c78c1faa1 100644 --- a/mpfr/print_raw.c +++ b/mpfr/print_raw.c @@ -1,21 +1,21 @@ /* mpfr_print_raw -- print the internal binary representation of a floating-point number -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -26,16 +26,10 @@ MA 02111-1307, USA. */ #include "mpfr.h" #include "mpfr-impl.h" -void mpfr_get_str_raw _PROTO ((char *, mpfr_srcptr)); +static void mpfr_get_str_raw _PROTO ((char *, mpfr_srcptr)); -void -#if __STDC__ +static void mpfr_get_str_raw (char *digit_ptr, mpfr_srcptr x) -#else -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; @@ -43,8 +37,6 @@ mpfr_get_str_raw (digit_ptr, x) ex = MPFR_EXP(x); p = MPFR_PREC(x); - /* TODO: utilite de gerer l'infini a ce niveau ? */ - if (MPFR_SIGN(x) < 0) { *digit_ptr = '-'; digit_ptr++; } sprintf(digit_ptr, "0."); digit_ptr += 2; @@ -52,7 +44,7 @@ mpfr_get_str_raw (digit_ptr, x) for (k = sx - 1; k >= 0 ; k--) { wd = mx[k]; - t = ((mp_limb_t)1) << (BITS_PER_MP_LIMB - 1); + t = MP_LIMB_T_HIGHBIT; for (l = BITS_PER_MP_LIMB - 1; l>=0; l--) { if (wd & t) @@ -67,12 +59,7 @@ mpfr_get_str_raw (digit_ptr, x) } void -#if __STDC__ -mpfr_print_raw(mpfr_srcptr x) -#else -mpfr_print_raw(x) - mpfr_srcptr x; -#endif +mpfr_print_raw (mpfr_srcptr x) { char *str; unsigned long alloc_size; diff --git a/mpfr/print_rnd_mode.c b/mpfr/print_rnd_mode.c index e97d74eba..0daf2dc90 100644 --- a/mpfr/print_rnd_mode.c +++ b/mpfr/print_rnd_mode.c @@ -1,43 +1,45 @@ /* mpfr_print_rnd_mode -- convert a given rounding mode to a string -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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 "mpfr.h" #include "gmp-impl.h" +#include "mpfr.h" char * -#if __STDC__ -mpfr_print_rnd_mode(mp_rnd_t rnd_mode) -#else -mpfr_print_rnd_mode(rnd_mode) - mp_rnd_t rnd_mode; -#endif +mpfr_print_rnd_mode (mp_rnd_t rnd_mode) { switch (rnd_mode) { - case GMP_RNDD: return("GMP_RNDD"); - case GMP_RNDU: return("GMP_RNDU"); - case GMP_RNDN: return("GMP_RNDN"); - case GMP_RNDZ: return("GMP_RNDZ"); - default: fprintf(stderr, "unknown rounding mode\n"); exit(1); + case GMP_RNDD: + return ("GMP_RNDD"); + case GMP_RNDU: + return ("GMP_RNDU"); + case GMP_RNDN: + return ("GMP_RNDN"); + case GMP_RNDZ: + return ("GMP_RNDZ"); + default: + fprintf (stderr, "unknown rounding mode\n"); + exit (1); } } diff --git a/mpfr/random.c b/mpfr/random.c index 64532b629..8e67922b2 100644 --- a/mpfr/random.c +++ b/mpfr/random.c @@ -1,20 +1,20 @@ /* mpfr_random -- generate a random floating-point number -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -29,12 +29,7 @@ MA 02111-1307, USA. */ /* Computes a random mpfr in [0, 1[ with precision MPFR_PREC */ void -#if __STDC__ mpfr_random (mpfr_ptr x) -#else -mpfr_random (x) - mpfr_ptr x; -#endif { mp_limb_t *xp; unsigned long xn, cnt, prec = MPFR_PREC(x); @@ -44,14 +39,18 @@ mpfr_random (x) mpn_random (xp, xn); - if (xp[xn - 1] == 0) xp[xn - 1] = 1; + 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); + if (cnt) + mpn_lshift (xp, xp, xn, cnt); MPFR_EXP(x) = -cnt; + if (MPFR_SIGN(x) < 0) + MPFR_CHANGE_SIGN(x); - cnt = xn*BITS_PER_MP_LIMB - prec; + 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_ONE << cnt) - MP_LIMB_T_ONE); } diff --git a/mpfr/random2.c b/mpfr/random2.c index f3384d0f4..8b42a7674 100644 --- a/mpfr/random2.c +++ b/mpfr/random2.c @@ -2,22 +2,23 @@ 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. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. +(Copied from the GNU MP Library.) -This file is part of the GNU MP Library. +This file is part of the MPFR 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 +The MPFR 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 +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 +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 Library General Public License -along with the GNU MP Library; see the file COPYING.LIB. If not, write to +You should have received a copy of the GNU Lesser 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. */ @@ -29,14 +30,7 @@ MA 02111-1307, USA. */ #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; @@ -65,5 +59,5 @@ mpfr_random2 (x, size, exp) 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); + xp[0] &= ~((MP_LIMB_T_ONE << cnt) - MP_LIMB_T_ONE); } diff --git a/mpfr/reldiff.c b/mpfr/reldiff.c index ea21a60b1..66597bcf4 100644 --- a/mpfr/reldiff.c +++ b/mpfr/reldiff.c @@ -1,20 +1,20 @@ /* mpfr_reldiff -- compute relative difference of two floating-point numbers. -Copyright (C) 2000 Free Software Foundation. +Copyright (C) 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -27,15 +27,7 @@ MA 02111-1307, USA. */ /* 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_reldiff (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mp_rnd_t rnd_mode) { mpfr_t b_copy; @@ -58,19 +50,21 @@ mpfr_reldiff(a, b, c, rnd_mode) } 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); + else + { + if (a == b) + { + mpfr_init2 (b_copy, MPFR_PREC(b)); + mpfr_set (b_copy, b, GMP_RNDN); + } - if (a == b) mpfr_clear (b_copy); - } + 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 dda40b5b4..85e303c67 100644 --- a/mpfr/rnd_mode.c +++ b/mpfr/rnd_mode.c @@ -1,20 +1,20 @@ /* mpfr_set_machine_rnd_mode -- set the rounding mode for machine floats -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -116,12 +116,7 @@ char *out; /* sets the machine rounding mode to the value rnd_mode */ void -#if __STDC__ -mpfr_set_machine_rnd_mode(mp_rnd_t rnd_mode) -#else -mpfr_set_machine_rnd_mode(rnd_mode) - mp_rnd_t rnd_mode; -#endif +mpfr_set_machine_rnd_mode (mp_rnd_t rnd_mode) { switch (rnd_mode) { case GMP_RNDN: TONEAREST; break; diff --git a/mpfr/round.c b/mpfr/round.c index a6de9bd50..182f38184 100644 --- a/mpfr/round.c +++ b/mpfr/round.c @@ -1,21 +1,21 @@ -/* mpfr_round_raw2, mpfr_round_raw, mpfr_round, mpfr_can_round, - mpfr_can_round_raw -- various rounding functions +/* mpfr_round_raw_generic, mpfr_round_raw2, mpfr_round_raw, mpfr_round, + mpfr_can_round, mpfr_can_round_raw -- various rounding functions -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -26,191 +26,178 @@ MA 02111-1307, USA. */ #include "mpfr.h" #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, - where sign=1 if neg=0, sign=-1 otherwise. - - Does *not* modify anything. -*/ -int -#if __STDC__ -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; - mp_prec_t xn; - int neg; - mp_rnd_t rnd; - mp_prec_t prec; +#if (BITS_PER_MP_LIMB & (BITS_PER_MP_LIMB - 1)) +#error "BITS_PER_MP_LIMB must be a power of 2" #endif -{ - 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; +/* + If flag = 0, 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. Supposes x is not zero nor NaN nor +/- Infinity + (i.e. *xp != 0). If inexp != NULL, computes the inexact flag of the + rounding. - if (rw) - mask = ~((((mp_limb_t)1)<<(BITS_PER_MP_LIMB - rw)) - 1); - else mask = ~((mp_limb_t)0); - - switch (rnd) - { - case GMP_RNDU: - case GMP_RNDD: - if (xp[xn - nw] & ~mask) return 1; - for (l = nw + 1;l <= xn; l++) - if (xp[xn - l]) break; - return (l <= xn); - - case GMP_RNDN: - /* First check if we are just halfway between two representable numbers */ - wd = xn - nw; - if (!rw) - { - if (!wd) /* all bits are significative */ return 0; - wd--; - if (xp[wd] == ((mp_limb_t)1 << (BITS_PER_MP_LIMB - 1))) - { - do wd--; while (wd > 0 && !xp[wd]); - if (!wd) { return 1; } else return xp[xn - nw] & 1; - } - - return xp[wd]>>(BITS_PER_MP_LIMB - 1); - } - else - if (rw + 1 < BITS_PER_MP_LIMB) - { - if ((xp[wd] & (~mask)) == (((mp_limb_t)1) << (BITS_PER_MP_LIMB - rw - 1))) - do { wd--; } while (wd >= 0 && !xp[wd]); - else return ((xp[wd]>>(BITS_PER_MP_LIMB - rw - 1)) & 1); - - /* first limb was in the middle, and others down to wd+1 were 0 */ - if (wd>=0) return 1; - else - return ((xp[xn - nw] & mask) >> (BITS_PER_MP_LIMB - rw)) & 1; - } - else - /* Modified PZ, 27 May 1999: - rw, i.e. the number of bits stored in xp[xn-nw], is - BITS_PER_MP_LIMB-1, i.e. there is exactly one non significant bit. - We are just halfway iff xp[wd] has its low significant bit - set and all limbs xp[0]...xp[wd-1] are zero */ - { - if (xp[wd] & 1) - do wd--; while (wd >= 0 && !xp[wd]); - return ((wd<0) ? xp[xn-nw]>>1 : xp[xn-nw]) & 1; - } - default: return 0; - } -} + In case of even rounding when rnd = GMP_RNDN, returns 2 or -2. -/* 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 - Supposes x is not zero nor NaN nor +/- Infinity (i.e. *xp != 0). + If flag = 1, just returns whether one should add 1 or not for rounding. */ + int -#if __STDC__ -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) - mp_limb_t *y; - mp_limb_t *xp; - mp_prec_t xprec; - char negative; - mp_prec_t yprec; - mp_rnd_t rnd_mode; -#endif +mpfr_round_raw_generic(mp_limb_t *yp, mp_limb_t *xp, mp_prec_t xprec, + int neg, mp_prec_t yprec, mp_rnd_t rnd_mode, + int *inexp, int flag) { - mp_prec_t nw, xsize; mp_limb_t mask; - char rw, carry = 0; + mp_size_t xsize, nw; + mp_limb_t himask, lomask; + int rw, carry = 0; xsize = (xprec-1)/BITS_PER_MP_LIMB + 1; - nw = yprec / BITS_PER_MP_LIMB; rw = yprec & (BITS_PER_MP_LIMB - 1); - if (rw) nw++; - /* number of words needed to represent x */ + nw = yprec / BITS_PER_MP_LIMB; + rw = yprec & (BITS_PER_MP_LIMB - 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 */ - if (xsize < nw) { - /* if y=xp, maybe an overlap: MPN_COPY_DECR is ok when src <= dst */ - MPN_COPY_DECR(y + nw - xsize, xp, xsize); - MPN_ZERO(y, nw - xsize); /* PZ 27 May 99 */ - y[0] &= mask; + if (flag && !inexp && (rnd_mode==GMP_RNDZ || xprec <= yprec + || (rnd_mode==GMP_RNDU && neg) + || (rnd_mode==GMP_RNDD && neg==0))) return 0; - } - if (mpfr_round_raw2(xp, xsize, negative, rnd_mode, yprec)) + if (rw) { - 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); + nw++; + lomask = ((MP_LIMB_T_ONE << (BITS_PER_MP_LIMB - rw)) - MP_LIMB_T_ONE); + himask = ~lomask; + } + else + { + lomask = -1; + himask = -1; + } + MPFR_ASSERTN(nw >= 1); + + if (xprec <= yprec) + { /* No rounding is necessary. */ + /* if yp=xp, maybe an overlap: MPN_COPY_DECR is ok when src <= dst */ + MPFR_ASSERTN(nw >= xsize); + if (inexp) + *inexp = 0; + if (flag) + return 0; + MPN_COPY_DECR(yp + (nw - xsize), xp, xsize); + MPN_ZERO(yp, nw - xsize); } - else /* now xsize >= nw */ - MPN_COPY_INCR(y, xp + xsize - nw, nw); + else + { + mp_limb_t sb; + + if ((rnd_mode == GMP_RNDU && neg) || + (rnd_mode == GMP_RNDD && !neg)) + rnd_mode = GMP_RNDZ; + + if (inexp || rnd_mode != GMP_RNDZ) + { + mp_size_t k; + + k = xsize - nw; + if (!rw) + k--; + MPFR_ASSERTN(k >= 0); + sb = xp[k] & lomask; /* First non-significant bits */ + if (rnd_mode == GMP_RNDN) + { + mp_limb_t rbmask = MP_LIMB_T_ONE << (BITS_PER_MP_LIMB - rw - 1); + if (sb & rbmask) /* rounding bit */ + sb &= ~rbmask; /* it is 1, clear it */ + else + rnd_mode = GMP_RNDZ; /* it is 0, behave like rounding to 0 */ + } + while (sb == 0 && k > 0) + sb = xp[--k]; + if (rnd_mode == GMP_RNDN) + { /* rounding to nearest, with rounding bit = 1 */ + if (sb == 0) /* Even rounding. */ + { + sb = xp[xsize - nw] & (himask ^ (himask << 1)); + if (inexp) + *inexp = ((neg != 0) ^ (sb != 0)) + ? MPFR_EVEN_INEX : -MPFR_EVEN_INEX; + } + else /* sb != 0 */ + { + if (inexp) + *inexp = (neg == 0) ? 1 : -1; + } + } + else if (inexp) + *inexp = sb == 0 ? 0 + : (((neg != 0) ^ (rnd_mode != GMP_RNDZ)) ? 1 : -1); + } + else + sb = 0; - y[0] &= mask; - return carry; + if (flag) + return sb != 0 && rnd_mode != GMP_RNDZ; + + if (sb != 0 && rnd_mode != GMP_RNDZ) + carry = mpn_add_1(yp, xp + xsize - nw, nw, + rw ? MP_LIMB_T_ONE << (BITS_PER_MP_LIMB - rw) : 1); + else + MPN_COPY_INCR(yp, xp + xsize - nw, nw); + + yp[0] &= himask; + } + + return carry; } -void -#if __STDC__ +int mpfr_round (mpfr_ptr x, mp_rnd_t rnd_mode, mp_prec_t prec) -#else -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, signx; mp_prec_t nw; + mp_limb_t *tmp; + int carry, neg, inexact; + 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); + if (MPFR_IS_NAN(x)) + MPFR_RET_NAN; + + if (MPFR_IS_INF(x)) + return 0; /* infinity is exact */ + + nw = 1 + (prec - 1) / BITS_PER_MP_LIMB; /* needed allocated limbs */ + neg = MPFR_SIGN(x) < 0; /* check if x has enough allocated space for the mantissa */ if (nw > MPFR_ABSSIZE(x)) { MPFR_MANT(x) = (mp_ptr) (*__gmp_reallocate_func) (MPFR_MANT(x), MPFR_ABSSIZE(x)*BYTES_PER_MP_LIMB, nw * BYTES_PER_MP_LIMB); MPFR_SIZE(x) = nw; /* new number of allocated limbs */ + if (neg) + MPFR_CHANGE_SIGN(x); } TMP_MARK(marker); tmp = TMP_ALLOC (nw * BYTES_PER_MP_LIMB); - carry = mpfr_round_raw(tmp, MPFR_MANT(x), MPFR_PREC(x), (MPFR_SIGN(x)<0), prec, - rnd_mode); + carry = mpfr_round_raw (tmp, MPFR_MANT(x), MPFR_PREC(x), neg, prec, rnd_mode, + &inexact); if (carry) - { - mpn_rshift(tmp, tmp, nw, 1); - tmp [nw-1] |= (((mp_limb_t)1) << (BITS_PER_MP_LIMB - 1)); - MPFR_EXP(x)++; + { + /* Is a shift necessary here? Isn't the result 1.0000...? */ + mpn_rshift (tmp, tmp, nw, 1); + tmp [nw-1] |= MP_LIMB_T_HIGHBIT; + MPFR_EXP(x)++; } - 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); + MPFR_PREC(x) = prec; + MPN_COPY(MPFR_MANT(x), tmp, nw); TMP_FREE(marker); -} -/* hypotheses : BITS_PER_MP_LIMB est une puissance de 2 - dans un test, la premiere partie du && est evaluee d'abord */ + return inexact; +} +/* assumptions: + (i) BITS_PER_MP_LIMB is a power of 2 + (ii) in a test, the left part of the && is evaluated first */ /* assuming b is an approximation of x in direction rnd1 with error at most 2^(MPFR_EXP(b)-err), returns 1 if one is @@ -220,58 +207,60 @@ mpfr_round (x, rnd_mode, prec) Side effects: none. */ -int -#if __STDC__ -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_ptr b; - mp_prec_t err; - mp_rnd_t rnd1; - mp_rnd_t rnd2; - mp_prec_t prec; -#endif +int +mpfr_can_round (mpfr_ptr b, mp_prec_t err, mp_rnd_t rnd1, + mp_rnd_t rnd2, mp_prec_t 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); + return (MPFR_IS_ZERO(b)) ? 0 : /* we cannot round if b=0 */ + 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, 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; - mp_prec_t bn; - int neg; - mp_prec_t err; - mp_rnd_t rnd1; - mp_rnd_t rnd2; - mp_prec_t prec; -#endif +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) { - int k, k1, l, l1, tn; mp_limb_t cc, cc2, *tmp; - TMP_DECL(marker); + int k, k1, l, l1, tn; + mp_limb_t cc, cc2, *tmp; + TMP_DECL(marker); - if (err<=prec) return 0; - neg = (neg > 0 ? 0 : 1); + if (err <= prec) + return 0; + neg = (neg > 0 ? 0 : 1); + + /* if the error is smaller than ulp(b), then anyway it will propagate + up to ulp(b) */ + if (err > bn * BITS_PER_MP_LIMB) + err = bn * BITS_PER_MP_LIMB; /* warning: if k = m*BITS_PER_MP_LIMB, consider limb m-1 and not m */ - k = (err-1)/BITS_PER_MP_LIMB; - l = err % BITS_PER_MP_LIMB; if (l) l = BITS_PER_MP_LIMB-l; - /* the error corresponds to bit l in limb k */ - k1 = (prec-1)/BITS_PER_MP_LIMB; - l1 = prec%BITS_PER_MP_LIMB; if (l1) l1 = BITS_PER_MP_LIMB-l1; + k = (err - 1) / BITS_PER_MP_LIMB; + l = err % BITS_PER_MP_LIMB; + if (l) + l = BITS_PER_MP_LIMB - l; + /* the error corresponds to bit l in limb k, the most significant limb + being limb 0 */ + k1 = (prec - 1) / BITS_PER_MP_LIMB; + l1 = prec % BITS_PER_MP_LIMB; + if (l1) + l1 = BITS_PER_MP_LIMB - l1; /* the last significant bit is bit l1 in limb k1 */ /* don't need to consider the k1 most significant limbs */ - k -= k1; bn -= k1; prec -= k1*BITS_PER_MP_LIMB; k1=0; - - if (rnd1==GMP_RNDU) { if (neg) rnd1=GMP_RNDZ; } - if (rnd1==GMP_RNDD) { if (neg) rnd1=GMP_RNDU; else rnd1=GMP_RNDZ; } + k -= k1; + bn -= k1; + prec -= k1 * BITS_PER_MP_LIMB; + k1=0; + /* if when adding or subtracting (1 << l) in bp[bn-1-k], it does not + change bp[bn-1] >> l1, then we can round */ + + if (rnd1 == GMP_RNDU) + if (neg) + rnd1 = GMP_RNDZ; + if (rnd1 == GMP_RNDD) + rnd1 = (neg) ? GMP_RNDU : GMP_RNDZ; /* in the sequel, RNDU = towards infinity, RNDZ = towards zero */ @@ -279,75 +268,77 @@ mpfr_can_round_raw(bp, bn, neg, err, rnd1, rnd2, prec) tn = bn; k++; /* since we work with k+1 everywhere */ - switch (rnd1) { - - 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); + switch (rnd1) + { + 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^(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 */ - if (cc2 && cc) { TMP_FREE(marker); return 0; } - cc2 = (tmp[bn-1]>>l1) & 1; /* gives 0 when carry */ - cc2 ^= mpfr_round_raw2(tmp, bn, neg, rnd2, prec); - - TMP_FREE(marker); + if (bn > k) + MPN_COPY (tmp, bp, bn - k); + cc2 = mpn_add_1 (tmp+bn-k, bp+bn-k, k, MP_LIMB_T_ONE << l); + /* if cc2=1, then all bits up to err were to 1, and we can round only + if cc==0 and mpfr_round_raw2 returns 0 below */ + if (cc2 && cc) + { + TMP_FREE(marker); + return 0; + } + cc2 = (tmp[bn-1]>>l1) & 1; /* gives 0 when carry */ + cc2 ^= mpfr_round_raw2(tmp, bn, neg, rnd2, prec); + + TMP_FREE(marker); return (cc == cc2); - 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^(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 */ - if (cc2 && cc) { TMP_FREE(marker); return 0; } - cc2 = (tmp[bn-1]>>l1) & 1; /* gives 1 when carry */ - cc2 ^= mpfr_round_raw2(tmp, bn, neg, rnd2, prec); - - TMP_FREE(marker); - return (cc == cc2); - - 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^(MPFR_EXP(b)-err-1) from b */ - - if (l) { - l--; /* tn=bn */ - mpn_sub_1(tmp+tn-k, bp+bn-k, k, (mp_limb_t)1<<l); - } - else { - MPN_COPY(tmp+1, bp, bn); *tmp=0; /* extra limb to add or subtract 1 */ - k++; l=BITS_PER_MP_LIMB-1; - mpn_sub_1(tmp+tn-k, tmp+tn-k, k, (mp_limb_t)1<<l); + 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^(MPFR_EXP(b)-err) */ + if (bn > k) + MPN_COPY (tmp, bp, bn - k); + cc2 = mpn_sub_1(tmp+bn-k, bp+bn-k, k, MP_LIMB_T_ONE << l); + /* if cc2=1, then all bits up to err were to 0, and we can round only + if cc==0 and mpfr_round_raw2 returns 1 below */ + if (cc2 && cc) + { + TMP_FREE(marker); + return 0; + } + cc2 = (tmp[bn-1]>>l1) & 1; /* gives 1 when carry */ + cc2 ^= mpfr_round_raw2(tmp, bn, neg, rnd2, prec); + + TMP_FREE(marker); + return (cc == cc2); + + case GMP_RNDN: /* b-2^(MPFR_EXP(b)-err) <= x <= b+2^(MPFR_EXP(b)-err) */ + tmp = TMP_ALLOC(tn * BYTES_PER_MP_LIMB); + + if (bn > k) + MPN_COPY (tmp, bp, bn - k); + /* first round b+2^(MPFR_EXP(b)-err) */ + cc = mpn_add_1 (tmp + bn - k, bp + bn - k, k, MP_LIMB_T_ONE << l); + cc = (tmp[bn - 1] >> l1) & 1; /* gives 0 when cc=1 */ + cc ^= mpfr_round_raw2 (tmp, bn, neg, rnd2, prec); + + /* now round b-2^(MPFR_EXP(b)-err) */ + cc2 = mpn_sub_1 (tmp + bn - k, bp + bn - k, k, MP_LIMB_T_ONE << l); + /* if cc2=1, then all bits up to err were to 0, and we can round only + if cc==0 and mpfr_round_raw2 returns 1 below */ + if (cc2 && cc) + { + TMP_FREE(marker); + return 0; + } + cc2 = (tmp[bn - 1] >> l1) & 1; /* gives 1 when cc2=1 */ + cc2 ^= mpfr_round_raw2 (tmp, bn, neg, rnd2, prec); + + TMP_FREE(marker); + return (cc == cc2); } - - /* 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^(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 */ - if (cc2 && cc) { TMP_FREE(marker); return 0; } - cc2 = (tmp[tn-1]>>l1) & 1; /* gives 0 when carry */ - cc2 ^= mpfr_round_raw2(tmp, tn, neg, rnd2, prec); - - TMP_FREE(marker); - return (cc == cc2); - } return 0; } diff --git a/mpfr/save_expo.c b/mpfr/save_expo.c new file mode 100644 index 000000000..fe451c548 --- /dev/null +++ b/mpfr/save_expo.c @@ -0,0 +1,62 @@ +/* Save/restore the minimum and maximum exponents. + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "mpfr.h" +#include "mpfr-impl.h" + +static unsigned int saved_flags; +static mp_exp_t saved_emin; +static mp_exp_t saved_emax; +static unsigned int save_ctr = 0; + +void +mpfr_save_emin_emax (void) +{ + if (save_ctr++ == 0) + { + saved_flags = __mpfr_flags; + saved_emin = __mpfr_emin; + saved_emax = __mpfr_emax; + __mpfr_emin = MPFR_EMIN_MIN; + __mpfr_emax = MPFR_EMAX_MAX; + } + else if (save_ctr == 0) + { + fprintf(stderr, + "Error: Too many consecutive calls to mpfr_save_emin_emax!\n" + "Probably a bug.\n"); + exit(1); + } +} + +void +mpfr_restore_emin_emax (void) +{ + if (--save_ctr == 0) + { + __mpfr_flags = saved_flags; + __mpfr_emin = saved_emin; + __mpfr_emax = saved_emax; + } +} diff --git a/mpfr/set.c b/mpfr/set.c index 9544d6d51..de78a476a 100644 --- a/mpfr/set.c +++ b/mpfr/set.c @@ -1,65 +1,76 @@ /* mpfr_set -- copy of a floating-point number -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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__ +/* set a to abs(b) * signb: a=b when signb = SIGN(b), a=abs(b) when signb=1 */ +int mpfr_set4 (mpfr_ptr a, mpfr_srcptr b, mp_rnd_t rnd_mode, int signb) -#else -mpfr_set4 (a, b, rnd_mode, signb) - mpfr_ptr a; - mpfr_srcptr b; - mp_rnd_t rnd_mode; - int signb; -#endif { - int carry, an, preca = MPFR_PREC(a), sh; mp_limb_t *ap = MPFR_MANT(a); + int inex; 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_SET_NAN(a); + MPFR_RET_NAN; } - 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; - if ((*ap >> sh) & 1) { - fprintf(stderr, "unable to round in mpfr_set\n"); exit(1); + + if (MPFR_IS_INF(b)) + { + MPFR_CLEAR_FLAGS(a); + MPFR_SET_INF(a); + inex = 0; } - mpn_rshift(ap, ap, an, 1); - ap[an-1] |= (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); - MPFR_EXP(a)++; - } - if (MPFR_SIGN(a) * signb < 0) MPFR_CHANGE_SIGN(a); + else + { + mp_limb_t *ap; + mp_prec_t aq; + int carry; + + MPFR_CLEAR_FLAGS(a); + + ap = MPFR_MANT(a); + aq = MPFR_PREC(a); + + carry = mpfr_round_raw(ap, MPFR_MANT(b), MPFR_PREC(b), (signb < 0), + aq, rnd_mode, &inex); + MPFR_EXP(a) = MPFR_EXP(b); + + if (carry) + { + mp_exp_t exp = MPFR_EXP(a); + + if (exp == __mpfr_emax) + return mpfr_set_overflow(a, rnd_mode, signb); + + MPFR_EXP(a)++; + ap[(MPFR_PREC(a)-1)/BITS_PER_MP_LIMB] = MP_LIMB_T_HIGHBIT; + } + } + + if (MPFR_SIGN(a) * signb < 0) + MPFR_CHANGE_SIGN(a); + MPFR_RET(inex); } diff --git a/mpfr/set_d.c b/mpfr/set_d.c index 50d87bb16..58c9c337c 100644 --- a/mpfr/set_d.c +++ b/mpfr/set_d.c @@ -1,21 +1,21 @@ /* mpfr_set_d, mpfr_get_d -- convert a multiple precision floating-point number from/to a machine double precision float -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -28,12 +28,14 @@ MA 02111-1307, USA. */ #if (BITS_PER_MP_LIMB==32) #define MPFR_LIMBS_PER_DOUBLE 2 -#elif (BITS_PER_MP_LIMB==64) +#elif (BITS_PER_MP_LIMB >= 64) #define MPFR_LIMBS_PER_DOUBLE 1 +#elif (BITS_PER_MP_LIMB == 16) +#define MPFR_LIMBS_PER_DOUBLE 4 #endif -int __mpfr_extract_double _PROTO ((mp_ptr, double, int)); -double __mpfr_scale2 _PROTO ((double, int)); +static int __mpfr_extract_double _PROTO ((mp_ptr, double, int)); +static double __mpfr_scale2 _PROTO ((double, int)); #define NaN (0./0.) /* ensures a machine-independent NaN */ #define Infp (1/0.) @@ -49,15 +51,8 @@ double __mpfr_scale2 _PROTO ((double, int)); #define _GMP_IEEE_FLOATS 0 #endif -int -#if __STDC__ +static int __mpfr_extract_double (mp_ptr rp, double d, int e) -#else -__mpfr_extract_double (rp, d, e) - mp_ptr rp; - double d; - int e; -#endif /* e=0 iff BITS_PER_MP_LIMB=32 and rp has only one limb */ { long exp; @@ -92,10 +87,10 @@ __mpfr_extract_double (rp, d, e) if (exp) { #if BITS_PER_MP_LIMB == 64 - manl = (((mp_limb_t) 1 << 63) + manl = ((MP_LIMB_T_ONE << 63) | ((mp_limb_t) x.s.manh << 43) | ((mp_limb_t) x.s.manl << 11)); #else - manh = ((mp_limb_t) 1 << 31) | (x.s.manh << 11) | (x.s.manl >> 21); + manh = (MP_LIMB_T_ONE << 31) | (x.s.manh << 11) | (x.s.manl >> 21); manl = x.s.manl << 11; #endif } @@ -174,14 +169,8 @@ __mpfr_extract_double (rp, d, e) /* End of part included from gmp-2.0.2 */ /* Part included from gmp temporary releases */ -double -#if __STDC__ +static double __mpfr_scale2 (double d, int exp) -#else -__mpfr_scale2 (d, exp) - double d; - int exp; -#endif { #if _GMP_IEEE_FLOATS { @@ -240,87 +229,101 @@ __mpfr_scale2 (d, exp) /* End of part included from gmp */ -void -#if __STDC__ +int mpfr_set_d (mpfr_ptr r, double d, mp_rnd_t rnd_mode) -#else -mpfr_set_d (r, d, rnd_mode) - mpfr_ptr r; - double d; - mp_rnd_t rnd_mode; -#endif { - int signd, sizer; unsigned int cnt; + int signd, sizer, sizetmp, inexact; + unsigned int cnt; + mpfr_ptr tmp; + TMP_DECL(marker); + TMP_MARK(marker); 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; + + 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 0; /* 0 is exact */ } - else if (DOUBLE_ISNAN(d)) { MPFR_SET_NAN(r); return; } + + else if (DOUBLE_ISNAN(d)) + { + MPFR_SET_NAN(r); + return 1; /* a NaN is always inexact */ + } + 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; + return 0; /* infinity is exact */ } + sizer = (MPFR_PREC(r) - 1) / BITS_PER_MP_LIMB + 1; + + /* warning: don't use tmp=r here, even if sizer >= MPFR_LIMBS_PER_DOUBLE, + since PREC(r) may be different from PREC(tmp), and then both variables + would have same precision in the mpfr_set4 call below. */ + tmp = (mpfr_ptr) TMP_ALLOC(sizeof(mpfr_t)); + MPFR_MANT(tmp) = TMP_ALLOC(MPFR_LIMBS_PER_DOUBLE * BYTES_PER_MP_LIMB); + MPFR_PREC(tmp) = 53; + MPFR_SIZE(tmp) = MPFR_LIMBS_PER_DOUBLE; + sizetmp = MPFR_LIMBS_PER_DOUBLE; + signd = (d < 0) ? -1 : 1; d = ABS (d); - 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) - MPFR_EXP(r) = __mpfr_extract_double (MPFR_MANT(r), d, 0); - else - MPFR_EXP(r) = __mpfr_extract_double (MPFR_MANT(r) + sizer - MPFR_LIMBS_PER_DOUBLE, d, 1); - - if (sizer > MPFR_LIMBS_PER_DOUBLE) - MPN_ZERO(MPFR_MANT(r), sizer - MPFR_LIMBS_PER_DOUBLE); + MPFR_EXP(tmp) = __mpfr_extract_double (MPFR_MANT(tmp), d, 1); - count_leading_zeros(cnt, MPFR_MANT(r)[sizer-1]); - if (cnt) mpn_lshift(MPFR_MANT(r), MPFR_MANT(r), sizer, cnt); + count_leading_zeros(cnt, MPFR_MANT(tmp)[sizetmp - 1]); + + if (cnt) + mpn_lshift (MPFR_MANT(tmp), MPFR_MANT(tmp), sizetmp, cnt); - MPFR_EXP(r) -= cnt; - if (MPFR_SIGN(r)*signd<0) MPFR_CHANGE_SIGN(r); + MPFR_EXP(tmp) -= cnt; + + /* tmp is exact since PREC(tmp)=53 */ + inexact = mpfr_set4(r, tmp, rnd_mode, signd); - mpfr_round(r, rnd_mode, MPFR_PREC(r)); - return; + TMP_FREE(marker); + return inexact; } double -#if __STDC__ -mpfr_get_d2(mpfr_srcptr src, long e) -#else -mpfr_get_d2(src, e) - mpfr_srcptr(src); - long e; -#endif +mpfr_get_d2 (mpfr_srcptr src, long e) { double res; mp_size_t size, i, n_limbs_to_use; mp_ptr qp; int negative; - if (MPFR_IS_NAN(src)) { + if (MPFR_IS_NAN(src)) + { #ifdef DEBUG - printf("recognized NaN\n"); + printf("recognized NaN\n"); #endif - return NaN; } - if (MPFR_IS_INF(src)) { + return NaN; + } + + if (MPFR_IS_INF(src)) + { #ifdef DEBUG - printf("Found Inf.\n"); + printf("Found Inf.\n"); #endif - return (MPFR_SIGN(src) == 1 ? Infp : Infm); - } - if (MPFR_NOTZERO(src)==0) return 0.0; + 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); @@ -345,7 +348,7 @@ mpfr_get_d2(src, e) #else #if (BITS_PER_MP_LIMB == 64) mp_limb_t q; - q = qp[size - i] & (mp_limb_t) 4294967295; + q = qp[size - i] & CNST_LIMB(0xFFFFFFFF); res = res / MP_BASE_AS_DOUBLE + ((negative) ? -(double)q : q); q = qp[size - i] - q; res = res + ((negative) ? -(double)q : q); @@ -358,13 +361,8 @@ mpfr_get_d2(src, e) } double -#if __STDC__ -mpfr_get_d(mpfr_srcptr src) -#else -mpfr_get_d(src) - mpfr_srcptr src; -#endif +mpfr_get_d (mpfr_srcptr src) { - return mpfr_get_d2(src, MPFR_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 ecfd11ac9..425638978 100644 --- a/mpfr/set_dfl_prec.c +++ b/mpfr/set_dfl_prec.c @@ -1,20 +1,20 @@ /* mpfr_set_default_prec, mpfr_get_default_prec -- set/get default precision -Copyright (C) 1999, 2000 Free Software Foundation. +Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -27,12 +27,7 @@ MA 02111-1307, USA. */ mp_prec_t __mpfr_default_fp_bit_precision = 53; void -#if __STDC__ mpfr_set_default_prec (mp_prec_t prec_in_bits) -#else -mpfr_set_default_prec (prec_in_bits) - mp_prec_t prec_in_bits; -#endif { __mpfr_default_fp_bit_precision = prec_in_bits; } diff --git a/mpfr/set_f.c b/mpfr/set_f.c index bcdacbfad..de4768a93 100644 --- a/mpfr/set_f.c +++ b/mpfr/set_f.c @@ -1,20 +1,20 @@ /* mpfr_set_f -- set a MPFR number from a GNU MPF number -Copyright (C) 1999-2000 Free Software Foundation. +Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -26,51 +26,58 @@ MA 02111-1307, USA. */ #include "mpfr.h" #include "mpfr-impl.h" -void -#if __STDC__ -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; - mp_rnd_t rnd_mode; -#endif +int +mpfr_set_f (mpfr_ptr y, mpf_srcptr x, mp_rnd_t rnd_mode) { - mp_limb_t *my, *mx, *tmp; unsigned long cnt, sx, sy; + mp_limb_t *my, *mx, *tmp; + unsigned long cnt, sx, sy; + int inexact; TMP_DECL(marker); - if (SIZ(x) * MPFR_SIGN(y) < 0) MPFR_CHANGE_SIGN(y); + if (SIZ(x) * MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN (y); - MPFR_CLEAR_FLAGS(y); + MPFR_CLEAR_FLAGS (y); - TMP_MARK(marker); - sx = ABS(SIZ(x)); sy = MPFR_ABSSIZE(y); - my = MPFR_MANT(y); mx = PTR(x); + sx = ABS(SIZ(x)); /* number of limbs of the mantissa of x */ + sy = 1 + (MPFR_PREC(y) - 1) / BITS_PER_MP_LIMB; + my = MPFR_MANT(y); + mx = PTR(x); - if (sx==0) { /* x is zero */ - MPFR_SET_ZERO(y); return; - } + if (sx == 0) /* x is zero */ + { + MPFR_SET_ZERO(y); + return 0; /* 0 is exact */ + } count_leading_zeros(cnt, mx[sx - 1]); - if (sy < sx) + if (sy <= sx) /* we may have to round even when sy = sx */ { unsigned long xprec = sx * BITS_PER_MP_LIMB; + TMP_MARK(marker); 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), MPFR_PREC(y), rnd_mode); + if (cnt) + mpn_lshift(tmp, mx, sx, cnt); + else + MPN_COPY(tmp, mx, sx); + mpfr_round_raw (my, tmp, xprec, (SIZ(x)<0), MPFR_PREC(y), rnd_mode, + &inexact); + TMP_FREE(marker); } else { - if (cnt) mpn_lshift(my + sy - sx, mx, sx, cnt); - else MPN_COPY(my + sy - sx, mx, sy); + if (cnt) + mpn_lshift(my + sy - sx, mx, sx, cnt); + else + MPN_COPY(my + sy - sx, mx, sy); MPN_ZERO(my, sy - sx); /* no rounding necessary, since y has a larger mantissa */ + inexact = 0; } MPFR_EXP(y) = EXP(x) * BITS_PER_MP_LIMB - cnt; - TMP_FREE(marker); + return inexact; } diff --git a/mpfr/set_prc_raw.c b/mpfr/set_prc_raw.c index b7a1633dd..c04318486 100644 --- a/mpfr/set_prc_raw.c +++ b/mpfr/set_prc_raw.c @@ -1,38 +1,33 @@ /* mpfr_set_prec_raw -- reset the precision of a floating-point number -Copyright (C) 2000 Free Software Foundation. +Copyright (C) 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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" 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); diff --git a/mpfr/set_prec.c b/mpfr/set_prec.c index 3f52e5b17..ebee34ed2 100644 --- a/mpfr/set_prec.c +++ b/mpfr/set_prec.c @@ -1,44 +1,38 @@ /* mpfr_set_prec -- reset the precision of a floating-point number -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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" -void -#if __STDC__ +int mpfr_set_prec (mpfr_ptr x, mp_prec_t p) -#else -mpfr_set_prec (x, p) - mpfr_ptr x; - mp_prec_t p; -#endif { mp_prec_t xsize; - if (p==0) { - printf("*** cannot set precision to 0 bits\n"); exit(1); - } + if (p == 0) + return 1; xsize = (p - 1)/BITS_PER_MP_LIMB + 1; /* new limb size */ @@ -49,15 +43,12 @@ mpfr_set_prec (x, p) } MPFR_PREC(x) = p; + + return MPFR_MANT(x) == NULL; } mp_prec_t -#if __STDC__ mpfr_get_prec (mpfr_srcptr x) -#else -mpfr_get_prec (x) - mpfr_srcptr x; -#endif { return MPFR_PREC(x); } diff --git a/mpfr/set_q.c b/mpfr/set_q.c index c6c364d6e..886a4c09f 100644 --- a/mpfr/set_q.c +++ b/mpfr/set_q.c @@ -1,20 +1,20 @@ /* mpfr_set_q -- set a floating-point number from a multiple-precision rational -Copyright (C) 2000 Free Software Foundation. +Copyright (C) 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -26,38 +26,30 @@ MA 02111-1307, USA. */ #include "longlong.h" /* set f to the rational q */ -void -#if __STDC__ +int 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_t n, d; + int inexact; MPFR_CLEAR_FLAGS(f); - num = mpq_numref(q); - sign = mpz_cmp_ui(num, 0); - if (sign==0) { - MPFR_SET_ZERO(f); - return; - } + num = mpq_numref (q); + if (mpz_cmp_ui (num, 0) == 0) + { + MPFR_SET_ZERO(f); + return 0; + } 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); + 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 */ + inexact = mpfr_div (f, n, d, rnd); + mpfr_clear (n); + mpfr_clear (d); + MPFR_RET(inexact); } diff --git a/mpfr/set_rnd.c b/mpfr/set_rnd.c index 34e728b8e..666488e98 100644 --- a/mpfr/set_rnd.c +++ b/mpfr/set_rnd.c @@ -1,20 +1,20 @@ /* mpfr_set_default_rounding_mode -- set the default rounding mode -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -26,12 +26,7 @@ MA 02111-1307, USA. */ 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 20abb0e7f..cb4fcc092 100644 --- a/mpfr/set_si.c +++ b/mpfr/set_si.c @@ -5,65 +5,79 @@ Copyright (C) 1999-2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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_set_si (mpfr_ptr x, long int i, mp_rnd_t rnd_mode) -#else -mpfr_set_si (x, i, rnd_mode) - mpfr_ptr x; - long int i; - mp_rnd_t rnd_mode; -#endif +int +mpfr_set_si (mpfr_ptr x, long i, mp_rnd_t rnd_mode) { - unsigned long xn, cnt; mp_limb_t ai, *xp; + int inex; + mp_size_t xn; + unsigned int cnt, nbits; + mp_limb_t ai, *xp; MPFR_CLEAR_FLAGS(x); - if (i==0) { MPFR_SET_ZERO(x); return; } - xn = (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB; - ai = (unsigned long) ABS(i); + if (i == 0) + { + MPFR_SET_ZERO(x); + if (MPFR_SIGN(x) < 0) + MPFR_CHANGE_SIGN(x); + MPFR_RET(0); + } - count_leading_zeros(cnt, ai); + xn = (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB; + ai = SAFE_ABS(long, i); + count_leading_zeros(cnt, ai); xp = MPFR_MANT(x); xp[xn] = ai << cnt; /* don't forget to put zero in lower limbs */ MPN_ZERO(xp, xn); - MPFR_EXP(x) = BITS_PER_MP_LIMB - cnt; + MPFR_EXP(x) = nbits = BITS_PER_MP_LIMB - cnt; + inex = mpfr_check_range(x, rnd_mode); + if (inex) + return inex; /* underflow or overflow */ /* 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); + if (MPFR_PREC(x) < nbits) + { + int carry; + + carry = mpfr_round_raw(xp+xn, xp+xn, nbits, (i < 0), MPFR_PREC(x), + rnd_mode, &inex); + if (carry) + { + mp_exp_t exp = MPFR_EXP(x); + + if (exp == __mpfr_emax) + return mpfr_set_overflow(x, rnd_mode, (ai < 0 ? -1 : 1)); + + MPFR_EXP(x)++; + xp[xn] = MP_LIMB_T_HIGHBIT; + } } - } /* warning: don't change the precision of x! */ - if (i*MPFR_SIGN(x) < 0) MPFR_CHANGE_SIGN(x); + if ((i < 0) ^ (MPFR_SIGN(x) < 0)) + MPFR_CHANGE_SIGN(x); - return; + MPFR_RET(inex); } diff --git a/mpfr/set_str.c b/mpfr/set_str.c index b97081765..7cde1c052 100644 --- a/mpfr/set_str.c +++ b/mpfr/set_str.c @@ -1,20 +1,20 @@ /* mpfr_set_str -- set a floating-point number from a string -Copyright (C) 2000 Free Software Foundation. +Copyright (C) 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -22,11 +22,7 @@ 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" @@ -34,15 +30,7 @@ MA 02111-1307, USA. */ #include "mpfr-impl.h" int -#if __STDC__ mpfr_set_str (mpfr_ptr x, __gmp_const char *str, int base, mp_rnd_t rnd_mode) -#else -mpfr_set_str (x, str, base, rnd_mode) - mpfr_ptr x; - __gmp_const char *str; - int base; - mp_rnd_t rnd_mode; -#endif { char negative = 0, *endptr; unsigned long k = 0, l, q; @@ -93,7 +81,7 @@ mpfr_set_str (x, str, base, rnd_mode) 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); + /* unexpected end of string */ return -1; } else { @@ -139,17 +127,9 @@ mpfr_set_str (x, str, base, rnd_mode) } 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_set_str (mpfr_ptr x, char *str, int base, mp_rnd_t rnd_mode) { - mpfr_init(x); - return mpfr_set_str(x, str, base, rnd_mode); + 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 4561daa46..6fbf831d8 100644 --- a/mpfr/set_str_raw.c +++ b/mpfr/set_str_raw.c @@ -1,31 +1,27 @@ /* mpfr_set_str_raw -- set a floating-point number from a binary string -Copyright (C) 1999-2001 Free Software Foundation. +Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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> -#ifdef HAS_STRING_H #include <string.h> -#else -#include <strings.h> -#endif #include "gmp.h" #include "gmp-impl.h" #include "longlong.h" @@ -37,13 +33,7 @@ MA 02111-1307, USA. */ to hold all the bits of str. */ void -#if __STDC__ mpfr_set_str_raw (mpfr_ptr x, char *str) -#else -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, alloc; mp_limb_t *xp; @@ -52,7 +42,6 @@ mpfr_set_str_raw (x, str) xp = MPFR_MANT(x); xsize = 1 + (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB; alloc = (strlen(str)+1) * sizeof(char); - str0 = str2 = (char *) (*__gmp_allocate_func) (alloc); if (*str == '-') { negative = 1; str++; } else if (*str == '+') str++; @@ -60,7 +49,8 @@ mpfr_set_str_raw (x, str) if (*str == 'I') { MPFR_SET_INF(x); - if (MPFR_ISNEG(x) != negative) MPFR_CHANGE_SIGN(x); + if (MPFR_ISNEG(x) != negative) + MPFR_CHANGE_SIGN(x); return; } @@ -72,6 +62,8 @@ mpfr_set_str_raw (x, str) MPFR_CLEAR_FLAGS(x); + str0 = str2 = (char *) (*__gmp_allocate_func) (alloc); + while (*str == '0') { str++; } while (*str == '0' || *str == '1') diff --git a/mpfr/set_ui.c b/mpfr/set_ui.c index 9fd88dd98..2ae08b7ff 100644 --- a/mpfr/set_ui.c +++ b/mpfr/set_ui.c @@ -5,64 +5,75 @@ Copyright (C) 1999-2001 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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_set_ui (mpfr_ptr x, unsigned long int i, mp_rnd_t rnd_mode) -#else -mpfr_set_ui (x, i, rnd_mode) - mpfr_ptr x; - unsigned long int i; - mp_rnd_t rnd_mode; -#endif +int +mpfr_set_ui (mpfr_ptr x, unsigned long i, mp_rnd_t rnd_mode) { - unsigned int xn, cnt; mp_limb_t *xp; + int inex = 0; 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); - - xp = MPFR_MANT(x); - xp[xn] = ((mp_limb_t) i) << cnt; - /* don't forget to put zero in lower limbs */ - 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); + if (i == 0) + MPFR_SET_ZERO(x); /* the sign will be set later */ + else + { + mp_size_t xn; + unsigned int cnt, nbits; + mp_limb_t *xp; + + xn = (MPFR_PREC(x)-1)/BITS_PER_MP_LIMB; + count_leading_zeros(cnt, (mp_limb_t) i); + + xp = MPFR_MANT(x); + xp[xn] = ((mp_limb_t) i) << cnt; + /* don't forget to put zero in lower limbs */ + MPN_ZERO(xp, xn); + + MPFR_EXP(x) = nbits = BITS_PER_MP_LIMB - cnt; + inex = mpfr_check_range(x, rnd_mode); + if (inex) + return inex; /* underflow or overflow */ + + /* round if MPFR_PREC(x) smaller than length of i */ + if (MPFR_PREC(x) < nbits) + { + int carry; + carry = mpfr_round_raw(xp+xn, xp+xn, nbits, 0, MPFR_PREC(x), + rnd_mode, &inex); + if (carry) + { + mp_exp_t exp = MPFR_EXP(x); + + if (exp == __mpfr_emax) + return mpfr_set_overflow(x, rnd_mode, 1); + + MPFR_EXP(x)++; + xp[xn] = MP_LIMB_T_HIGHBIT; + } + } } - } /* warning: don't change the precision of x! */ - if (MPFR_SIGN(x) < 0) MPFR_CHANGE_SIGN(x); + if (MPFR_SIGN(x) < 0) + MPFR_CHANGE_SIGN(x); - return; + MPFR_RET(inex); } - diff --git a/mpfr/set_z.c b/mpfr/set_z.c index 0815ca324..742b806ac 100644 --- a/mpfr/set_z.c +++ b/mpfr/set_z.c @@ -1,20 +1,20 @@ /* mpfr_set_z -- set a floating-point number from a multiple-precision integer -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -27,16 +27,11 @@ MA 02111-1307, USA. */ /* set f to the integer z */ int -#if __STDC__ 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; - mp_rnd_t rnd; -#endif { - int fn, zn, k, dif, sign_z, sh; mp_limb_t *fp = MPFR_MANT(f), *zp, cc, c2; + mp_size_t fn, zn, dif, sh; + int k, sign_z; + mp_limb_t *fp = MPFR_MANT(f), *zp, cc, c2; MPFR_CLEAR_FLAGS (f); /* z cannot be NaN nor Inf */ @@ -61,12 +56,12 @@ mpfr_set_z (f, z, rnd) } else MPN_COPY(fp, zp + dif, fn); sh = fn*BITS_PER_MP_LIMB-MPFR_PREC(f); - cc = *fp & (((mp_limb_t)1 << sh) - 1); + cc = *fp & ((MP_LIMB_T_ONE << sh) - 1); *fp = *fp & ~cc; if (rnd==GMP_RNDN) { - if (sh) c2 = (mp_limb_t)1 << (sh-1); + if (sh) c2 = MP_LIMB_T_ONE << (sh - 1); else { /* sh=0 */ - c2 = ((mp_limb_t)1) << (BITS_PER_MP_LIMB-1); + c2 = MP_LIMB_T_HIGHBIT; dif--; cc = (dif>=0) ? ((zp[dif])<<k) : 0; if (dif>0 && k) cc += zp[dif-1] >> (BITS_PER_MP_LIMB-k); @@ -79,7 +74,7 @@ mpfr_set_z (f, z, rnd) while (dif>0 && (cc=zp[dif-1])==0) dif--; if (cc) { mpfr_add_one_ulp(f); return cc; } else /* exactly in middle: inexact in both cases */ - if (*fp & ((mp_limb_t)1<<sh)) { mpfr_add_one_ulp(f); return 1; } + if (*fp & (MP_LIMB_T_ONE << sh)) { mpfr_add_one_ulp(f); return 1; } else return 1; } } diff --git a/mpfr/sin.c b/mpfr/sin.c new file mode 100644 index 000000000..524570e6e --- /dev/null +++ b/mpfr/sin.c @@ -0,0 +1,78 @@ +/* mpfr_sin -- sine of a floating-point number + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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_sin (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode) +{ + int precy, m, ok, e, inexact; + mpfr_t c; + + if (MPFR_IS_NAN(x) || MPFR_IS_INF(x)) + { + MPFR_SET_NAN(y); + return 1; /* inexact */ + } + + if (!MPFR_NOTZERO(x)) + { + mpfr_set_ui (y, 0, GMP_RNDN); + return 0; /* exact */ + } + + precy = MPFR_PREC(y); + m = precy + _mpfr_ceil_log2 ((double) precy) + ABS(MPFR_EXP(x)) + 13; + + mpfr_init2 (c, m); + + do + { + mpfr_cos (c, x, GMP_RNDZ); + mpfr_mul (c, c, c, GMP_RNDU); + mpfr_ui_sub (c, 1, c, GMP_RNDN); + e = 2 + (-MPFR_EXP(c)) / 2; + mpfr_sqrt (c, c, GMP_RNDN); + if (mpfr_cmp_ui (x, 0) < 0) + mpfr_neg (c, c, GMP_RNDN); + + /* the absolute error on c is at most 2^(e-m) = 2^(EXP(c)-err) */ + e = MPFR_EXP(c) + m - e; + ok = (e >= 0) && mpfr_can_round (c, e, GMP_RNDN, rnd_mode, precy); + + if (ok == 0) + { + m += BITS_PER_MP_LIMB; + mpfr_set_prec (c, m); + } + } + while (!ok); + + inexact = mpfr_set (y, c, rnd_mode); + + mpfr_clear (c); + + return inexact; /* inexact */ +} diff --git a/mpfr/sinh.c b/mpfr/sinh.c new file mode 100644 index 000000000..2646aad4b --- /dev/null +++ b/mpfr/sinh.c @@ -0,0 +1,135 @@ +/* mpfr_sinh -- hyperbolic sine + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + + /* The computation of cosh is done by + + cosh= 1/2[e^(x)-e^(-x)] + */ + +int +mpfr_sinh (mpfr_ptr y, mpfr_srcptr xt , mp_rnd_t rnd_mode) +{ + /****** Declaration ******/ + mpfr_t x; + mp_prec_t Nxt = MPFR_PREC(xt); + int flag_neg=0, inexact =0; + + if (MPFR_IS_NAN(xt)) + { + MPFR_SET_NAN(y); + return 1; + } + MPFR_CLEAR_NAN(y); + + if (MPFR_IS_INF(xt)) + { + MPFR_SET_INF(y); + MPFR_SET_SAME_SIGN(y,xt); + return 0; + } + + MPFR_CLEAR_INF(y); + + if(!MPFR_NOTZERO(xt)) + { + MPFR_SET_ZERO(y); /* sinh(0) = 0 */ + MPFR_SET_SAME_SIGN(y,xt); + return(0); + } + + mpfr_init2(x,Nxt); + mpfr_set(x,xt,GMP_RNDN); + + if(MPFR_SIGN(x)<0) + { + MPFR_CHANGE_SIGN(x); + flag_neg=1; + } + + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t t, te,ti; + int d; + + /* Declaration of the size variable */ + mp_prec_t Nx = Nxt; /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ + + mp_prec_t Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt = Nt+_mpfr_ceil_log2(5)+_mpfr_ceil_log2(Nt); + + /* initialise of intermediary variable */ + mpfr_init(t); + mpfr_init(te); + mpfr_init(ti); + + + /* First computation of cosh */ + do { + + /* reactualisation of the precision */ + + mpfr_set_prec(t,Nt); + mpfr_set_prec(te,Nt); + mpfr_set_prec(ti,Nt); + + /* compute sinh */ + mpfr_exp(te,x,GMP_RNDD); /* exp(x) */ + mpfr_ui_div(ti,1,te,GMP_RNDU); /* 1/exp(x) */ + mpfr_sub(t,te,ti,GMP_RNDN); /* exp(x) - 1/exp(x)*/ + mpfr_div_2exp(t,t,1,GMP_RNDN); /* 1/2(exp(x) - 1/exp(x))*/ + + /* calculation of the error*/ + d = MPFR_EXP(te)-MPFR_EXP(t)+2; + + /* estimation of the error */ + /* err = Nt-(_mpfr_ceil_log2(1+pow(2,d)));*/ + err = Nt-(MAX(d,0)+1); + + /* actualisation of the precision */ + Nt += 10; + + } while ((err < 0) || !mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny)); + + if (flag_neg==1) + MPFR_CHANGE_SIGN(t); + + inexact = mpfr_set(y,t,rnd_mode); + mpfr_clear(t); + mpfr_clear(ti); + mpfr_clear(te); + } + mpfr_clear(x); + return inexact; + +} diff --git a/mpfr/sqrt.c b/mpfr/sqrt.c index 8489581bd..839f769bd 100644 --- a/mpfr/sqrt.c +++ b/mpfr/sqrt.c @@ -1,20 +1,20 @@ /* mpfr_sqrt -- square root of a floating-point number -Copyright (C) 1999, 2001 Free Software Foundation. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -29,14 +29,7 @@ MA 02111-1307, USA. */ /* #define DEBUG */ int -#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; @@ -44,25 +37,25 @@ mpfr_sqrt (r, u, rnd_mode) mp_size_t prec, err; mp_limb_t q_limb; long rw, nw, k; - int exact = 0, t; + int inexact = 0, t; unsigned long cc = 0; char can_round = 0; TMP_DECL(marker0); if (MPFR_IS_NAN(u)) { MPFR_SET_NAN(r); - return 1; + return 1; /* NaN is always inexact */ } if (MPFR_SIGN(u) < 0) { if (MPFR_IS_INF(u) || MPFR_NOTZERO(u)) { MPFR_SET_NAN(r); - return 1; + return 1; /* NaN is always inexact */ } else { /* sqrt(-0) = -0 */ MPFR_SET_ZERO(r); if (MPFR_SIGN(r) > 0) MPFR_CHANGE_SIGN(r); - return 0; + return 0; /* zero is exact */ } } @@ -72,7 +65,7 @@ mpfr_sqrt (r, u, rnd_mode) if (MPFR_IS_INF(u)) { MPFR_SET_INF(r); - return 1; + return 0; /* infinity is exact */ } MPFR_CLEAR_INF(r); @@ -84,11 +77,10 @@ mpfr_sqrt (r, u, rnd_mode) MPFR_EXP(r) = 0; rsize = (prec-1)/BITS_PER_MP_LIMB + 1; MPN_ZERO(MPFR_MANT(r), rsize); - return 0; + return 0; /* zero is exact */ } up = MPFR_MANT(u); - usize = (MPFR_PREC(u) - 1)/BITS_PER_MP_LIMB + 1; #ifdef DEBUG @@ -121,7 +113,7 @@ mpfr_sqrt (r, u, rnd_mode) { up = TMP_ALLOC((usize + 1)*BYTES_PER_MP_LIMB); if (mpn_rshift(up + 1, MPFR_MANT(u), usize, 1)) - up [0] = ((mp_limb_t) 1) << (BITS_PER_MP_LIMB - 1); + up [0] = MP_LIMB_T_HIGHBIT; else up[0] = 0; usize++; } @@ -164,14 +156,15 @@ mpfr_sqrt (r, u, rnd_mode) q_limb = mpn_sqrtrem (rp, remp, tmp, rsize); #ifdef DEBUG - printf("The result is : \n"); - printf("sqrt : "); - for(k = rrsize - 1; k >= 0; k--) { printf("%lu ", rp[k]); } - printf("(q_limb = %lu)\n", q_limb); + printf ("The result is : \n"); + printf ("sqrt : "); + for (k = rrsize - 1; k >= 0; k--) + printf ("%lu ", rp[k]); + printf ("(inexact = %lu)\n", q_limb); #endif - can_round = (mpfr_can_round_raw(rp, rrsize, 1, err, - GMP_RNDZ, rnd_mode, MPFR_PREC(r))); + can_round = mpfr_can_round_raw(rp, rrsize, 1, err, + 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 */ @@ -186,67 +179,87 @@ mpfr_sqrt (r, u, rnd_mode) } while (!can_round && (rsize < 2*usize) && (rsize += 2) && (rrsize ++)); - +#ifdef DEBUG + printf ("can_round = %d\n", can_round); +#endif /* This part may be deplaced upper to avoid a few mpfr_can_round_raw */ /* when the square root is exact. It is however very unprobable that */ /* it would improve the behaviour of the present code on average. */ - if (!q_limb) /* possibly exact */ + if (!q_limb) /* the sqrtrem call was exact, possible exact square root */ { /* if we have taken into account the whole of up */ for (k = usize - rsize - 1; k >= 0; k ++) if (up[k]) break; - if (k < 0) { exact = 1; goto fin; } + if (k < 0) + goto fin; /* exact square root ==> inexact = 0 */ } if (can_round) { - cc = mpfr_round_raw(rp, rp, err, 0, MPFR_PREC(r), rnd_mode); + cc = mpfr_round_raw (rp, rp, err, 0, MPFR_PREC(r), rnd_mode, &inexact); + if (!inexact) /* exact high part: inexact flag depends from remainder */ + inexact = -q_limb; rrsize = (MPFR_PREC(r) - 1)/BITS_PER_MP_LIMB + 1; } else /* Use the return value of sqrtrem to decide of the rounding */ /* Note that at this point the sqrt has been computed */ - /* EXACTLY. If rounding = GMP_RNDZ, do nothing [comes from */ - /* the fact that the exact square root can end with a bunch of ones, */ - /* and in that case we indeed cannot round if we do not know that */ - /* the computation was exact. */ + /* EXACTLY. */ switch (rnd_mode) { case GMP_RNDZ : - case GMP_RNDD : break; + case GMP_RNDD : + inexact = -1; /* result is truncated */ + break; case GMP_RNDN : /* Not in the situation ...0 111111 */ 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) + { + rw = BITS_PER_MP_LIMB - rw; + nw = 0; + } + else + nw = 1; if ((rp[nw] >> rw) & 1 && /* Not 0111111111 */ (q_limb || /* Nonzero remainder */ (rw ? (rp[nw] >> (rw + 1)) & 1 : (rp[nw] >> (BITS_PER_MP_LIMB - 1)) & 1))) /* or even rounding */ - cc = mpn_add_1(rp + nw, rp + nw, rrsize, ((mp_limb_t)1) << rw); + { + cc = mpn_add_1 (rp + nw, rp + nw, rrsize, MP_LIMB_T_ONE << rw); + inexact = 1; + } + else + inexact = -1; break; - case GMP_RNDU : - if (q_limb) - { - 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); - } + case GMP_RNDU: + /* we should arrive here only when the result is inexact, + i.e. either q_limb > 0 (the remainder from mpn_sqrtrem is non-zero) + or up[0..usize-rsize-1] is non zero, thus we have to add one + ulp, and inexact = 1 */ + inexact = 1; + t = MPFR_PREC(r) & (BITS_PER_MP_LIMB - 1); + rsize = (MPFR_PREC(r) - 1)/BITS_PER_MP_LIMB + 1; + if (t) + cc = mpn_add_1 (rp + rrsize - rsize, rp + rrsize - rsize, rsize, + MP_LIMB_T_ONE << (BITS_PER_MP_LIMB - t)); + else + cc = mpn_add_1 (rp + rrsize - rsize, rp + rrsize - rsize, rsize, + MP_LIMB_T_ONE); } - if (cc) { - mpn_rshift(rp, rp, rrsize, 1); - rp[rrsize-1] |= (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); - MPFR_EXP(r)++; - } + if (cc) + { + /* Is a shift necessary here? Isn't the result 1.0000...? */ + mpn_rshift (rp, rp, rrsize, 1); + rp[rrsize-1] |= MP_LIMB_T_HIGHBIT; + MPFR_EXP(r)++; + } fin: rsize = rrsize; @@ -254,11 +267,11 @@ mpfr_sqrt (r, u, rnd_mode) MPN_COPY(MPFR_MANT(r), rp + rsize - rrsize, rrsize); if (MPFR_PREC(r) & (BITS_PER_MP_LIMB - 1)) - MPFR_MANT(r) [0] &= ~(((mp_limb_t)1 << (BITS_PER_MP_LIMB - + MPFR_MANT(r) [0] &= ~((MP_LIMB_T_ONE << (BITS_PER_MP_LIMB - (MPFR_PREC(r) & (BITS_PER_MP_LIMB - 1)))) - 1) ; TMP_FREE (marker); } TMP_FREE(marker0); - return exact; + return inexact; } diff --git a/mpfr/sqrt_ui.c b/mpfr/sqrt_ui.c index 3453e3d0f..4e044c137 100644 --- a/mpfr/sqrt_ui.c +++ b/mpfr/sqrt_ui.c @@ -1,20 +1,20 @@ /* mpfr_sqrt_ui -- square root of a machine integer -Copyright (C) 2000 Free Software Foundation. +Copyright (C) 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -28,31 +28,25 @@ MA 02111-1307, USA. */ #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; + if (u) + { + mpfr_t uu; + mp_limb_t up[1]; + unsigned long cnt; + + 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; + + return mpfr_sqrt(r, uu, rnd_mode); + } + else /* sqrt(0) = 0 */ + { + MPFR_CLEAR_FLAGS(r); + MPFR_SET_ZERO(r); + return 0; + } } diff --git a/mpfr/sub.c b/mpfr/sub.c index 9fda68d49..e830bf692 100644 --- a/mpfr/sub.c +++ b/mpfr/sub.c @@ -1,608 +1,152 @@ /* mpfr_sub -- subtract two floating-point numbers -Copyright (C) 1999 Free Software Foundation. +Copyright (C) 2001 Free Software Foundation. +Contributed by the Spaces project, INRIA Lorraine. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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 */ - -#define ONE ((mp_limb_t) 1) - -extern void mpfr_add1 _PROTO((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, - mp_rnd_t, int)); -mp_limb_t mpn_sub_lshift_n _PROTO ((mp_limb_t *, mp_limb_t *, int, int, int)); -void mpfr_sub1 _PROTO ((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 < 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; -#endif +int +mpfr_sub (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mp_rnd_t rnd_mode) { - mp_limb_t c, bh=0; - - /* shift b to the left */ - if (sh) bh = mpn_lshift(bp, bp, n, sh); - c = (n<an) ? mpn_sub_n(ap, bp, ap, n) : mpn_sub_n(ap, bp+(n-an), ap, an); - /* shift back b to the right */ - if (sh) { - mpn_rshift(bp, bp, n, sh); - bp[n-1] += bh<<(BITS_PER_MP_LIMB-sh); + if (MPFR_IS_NAN(b) || MPFR_IS_NAN(c)) + { + MPFR_SET_NAN(a); + MPFR_RET_NAN; } - return c; -} -/* 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, - mp_rnd_t rnd_mode, int diff_exp) -#else -mpfr_sub1 (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 -{ - mp_limb_t *ap, *bp, *cp, cc, c2; unsigned int an, bn, cn; - int sh,dif,k,cancel,cancel1,cancel2; - TMP_DECL(marker); + MPFR_CLEAR_NAN(a); -#ifdef DEBUG - printf("b= "); if (MPFR_SIGN(b)>=0) putchar(' '); - mpfr_print_raw(b); putchar('\n'); - 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 (MPFR_PREC(a)+cancel) bits from b */ - cancel1 = cancel/BITS_PER_MP_LIMB; cancel2 = cancel%BITS_PER_MP_LIMB; - TMP_MARK(marker); - ap = MPFR_MANT(a); - bp = MPFR_MANT(b); - cp = MPFR_MANT(c); - if (ap == bp) { - 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) + if (MPFR_IS_INF(b)) + { + if (!MPFR_IS_INF(c) || MPFR_SIGN(b) != MPFR_SIGN(c)) { - cp = (mp_ptr) TMP_ALLOC (MPFR_ABSSIZE(c) * BYTES_PER_MP_LIMB); - MPN_COPY(cp, ap, MPFR_ABSSIZE(c)); - } - 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 (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 = MPFR_PREC(a)-diff_exp; -#ifdef DEBUG - 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>=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 > 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 (MPFR_NOTZERO(c)) { /* c is not zero */ - /* check whether mant(c)=1/2 or not */ - cc = *cp - (ONE<<(BITS_PER_MP_LIMB-1)); - if (cc==0) { - bp = cp+(MPFR_PREC(c)-1)/BITS_PER_MP_LIMB; - while (cp<bp && cc==0) cc = *++cp; - } - 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] = ONE << (BITS_PER_MP_LIMB-1); - MPFR_EXP(a)++; - } - } - 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] = ONE << (BITS_PER_MP_LIMB-1); - MPFR_EXP(a)++; - } - } - else { - /* round down: subtract 1 ulp iff c<>0 */ - if (MPFR_NOTZERO(c)) goto sub_one_ulp; - } + MPFR_SET_INF(a); + MPFR_SET_SAME_SIGN(a, b); + MPFR_RET(0); /* exact */ } - 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); - { /* treat all rounding modes together */ - mp_limb_t c2old; int sign=0; long int cout=0; - - if (sh) { - cc = *ap & ((ONE<<sh)-1); - *ap &= ~cc; /* truncate last bits */ - } - 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 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 (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); - } - } - 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; - } - 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 + { + MPFR_SET_NAN(a); + MPFR_RET_NAN; } } - 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)/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 - destroyed in case dif<0 */ - } -#ifdef DEBUG - printf("cancel=%d dif=%d k=%d cn=%d sh=%d\n",cancel,dif,k,cn,sh); -#endif - 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]<<(BITS_PER_MP_LIMB-dif); - } - else if (dif<0) { - 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]>>(BITS_PER_MP_LIMB+dif); - } - 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<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) { - 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]>>(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_COPY(ap+(an-cn), cp, cn); - } - else { /* shift to the right by -overlap bits */ - overlap = -overlap; - 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); - cc = 0; - } - if (an>k+cn) ap[an-k-cn-1]=cc; - } - overlap=0; - } -#ifdef DEBUG - printf("1:a="); mpfr_print_raw(a); putchar('\n'); -#endif - /* here overlap=1 iff ulp(c)<ulp(a) */ - /* then put high limbs to zero */ - /* now add 'an' upper limbs of b in place */ - if (MPFR_PREC(b)<=MPFR_PREC(a)+cancel) { int i, imax; - overlap += 2; - /* invert low limbs */ - 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; - 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 /* 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 - printf("2:a="); mpfr_print_raw(a); putchar('\n'); - printf("overlap=%d\n",overlap); -#endif - if (rnd_mode==GMP_RNDN) { /* to nearest */ - int kc; - /* four cases: overlap = - (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 */ - 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; - } - /* 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 */ - k=bn-an; dif=0; goto to_nearest; - /* otherwise the result is exact: nothing to do */ - } - } - 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 */ - 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 */ - 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]<<(BITS_PER_MP_LIMB-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: 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]<<(BITS_PER_MP_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 round to zero: remove 1 ulp if neglected bits from b-c are < 0 */ - 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) { - 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]<<(BITS_PER_MP_LIMB-dif) : 0; - while (cc==0 && cn>0) cc = cp[--cn]; - if (cc) goto sub_one_ulp; - break; - } - } + else + if (MPFR_IS_INF(c)) + { + MPFR_SET_INF(a); + if (MPFR_SIGN(c) == MPFR_SIGN(a)) + MPFR_CHANGE_SIGN(a); + MPFR_RET(0); /* exact */ } - } - goto end_of_sub; - - 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 & ((ONE<<sh)-1); - *ap &= ~cc; /* truncate last bits */ - c2 = ONE<<(sh-1); - } - else /* no bit to truncate */ - { 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 - 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]; -#ifdef DEBUG - printf("cc=%lu\n",cc); -#endif - /* special case of rouding c shifted to the right */ - 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 & (ONE<<sh))) goto add_one_ulp; - } - else { - /* subtract: if cc>0, do nothing */ - if (cc==0 && (*ap & (ONE<<sh))) goto add_one_ulp; - } - } - goto end_of_sub; - - sub_one_ulp: - 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, ONE<<sh); - - end_of_sub: -#ifdef DEBUG -printf("b-c="); if (MPFR_SIGN(a)>0) putchar(' '); mpfr_print_raw(a); putchar('\n'); -#endif - TMP_FREE(marker); - return; -} - -void -#if __STDC__ -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_srcptr b; - mpfr_srcptr c; - mp_rnd_t rnd_mode; -#endif -{ - int diff_exp; - - if (MPFR_IS_NAN(b) || MPFR_IS_NAN(c)) { - MPFR_SET_NAN(a); - return; - } - - MPFR_CLEAR_NAN(a); + MPFR_ASSERTN(MPFR_IS_FP(b) && MPFR_IS_FP(c)); - 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; + if (MPFR_IS_ZERO(b)) + { + if (MPFR_IS_ZERO(c)) + { + if (MPFR_SIGN(a) != + (rnd_mode != GMP_RNDD ? + ((MPFR_SIGN(b) < 0 && MPFR_SIGN(c) > 0) ? -1 : 1) : + ((MPFR_SIGN(b) > 0 && MPFR_SIGN(c) < 0) ? 1 : -1))) + MPFR_CHANGE_SIGN(a); + MPFR_CLEAR_INF(a); + MPFR_SET_ZERO(a); + MPFR_RET(0); /* 0 - 0 is exact */ } - else - if (MPFR_IS_INF(c)) - { - MPFR_SET_INF(a); - if (MPFR_SIGN(c) == MPFR_SIGN(a)) { MPFR_CHANGE_SIGN(a); } - return; - } + return mpfr_neg (a, c, rnd_mode); + } - if (!MPFR_NOTZERO(b)) { mpfr_neg(a, c, rnd_mode); return; } - if (!MPFR_NOTZERO(c)) { mpfr_set(a, b, rnd_mode); return; } + if (MPFR_IS_ZERO(c)) + { + return mpfr_set (a, b, rnd_mode); + } MPFR_CLEAR_INF(a); - 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); + if (MPFR_SIGN(b) == MPFR_SIGN(c)) + { /* signs are equal, it's a real subtraction */ + if (MPFR_EXP(b) < MPFR_EXP(c)) + { /* exchange rounding modes towards +/- infinity */ + int inexact; + if (rnd_mode == GMP_RNDU) + rnd_mode = GMP_RNDD; + else if (rnd_mode == GMP_RNDD) + rnd_mode = GMP_RNDU; + inexact = - mpfr_sub1(a, c, b, rnd_mode, + (mp_exp_unsigned_t) MPFR_EXP(c) - MPFR_EXP(b)); MPFR_CHANGE_SIGN(a); + return inexact; } - 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) 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); - MPFR_CHANGE_SIGN(a); + else if (MPFR_EXP(b) > MPFR_EXP(c)) + return mpfr_sub1(a, b, c, rnd_mode, + (mp_exp_unsigned_t) MPFR_EXP(b) - MPFR_EXP(c)); + else + { /* MPFR_EXP(b) == MPFR_EXP(c) */ + int d = mpfr_cmp_abs (b, c); + + if (d == 0) + { + if (rnd_mode == GMP_RNDD) + MPFR_SET_NEG(a); + else + MPFR_SET_POS(a); + MPFR_SET_ZERO(a); + MPFR_RET(0); + } + else if (d > 0) + return mpfr_sub1 (a, b, c, rnd_mode, 0); + else + { /* exchange rounding modes towards +/- infinity */ + int inexact; + if (rnd_mode == GMP_RNDU) + rnd_mode = GMP_RNDD; + else if (rnd_mode == GMP_RNDD) + rnd_mode = GMP_RNDU; + inexact = - mpfr_sub1 (a, c, b, rnd_mode, 0); + MPFR_CHANGE_SIGN(a); + return inexact; } } } - else /* signs differ, it's an addition */ - 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_add1(a, c, b, rnd_mode, -diff_exp); - MPFR_CHANGE_SIGN(a); + else + { /* signs differ, it's an addition */ + if (MPFR_EXP(b) < MPFR_EXP(c)) + { /* exchange rounding modes towards +/- infinity */ + int inexact; + if (rnd_mode == GMP_RNDU) + rnd_mode = GMP_RNDD; + else if (rnd_mode == GMP_RNDD) + rnd_mode = GMP_RNDU; + inexact = mpfr_add1(a, c, b, rnd_mode, + (mp_exp_unsigned_t) MPFR_EXP(c) - MPFR_EXP(b)); + MPFR_CHANGE_SIGN(a); + return inexact; } - else mpfr_add1(a, b, c, rnd_mode, diff_exp); + else + { + return mpfr_add1(a, b, c, rnd_mode, + (mp_exp_unsigned_t) MPFR_EXP(b) - MPFR_EXP(c)); + } + } } - diff --git a/mpfr/sub1.c b/mpfr/sub1.c new file mode 100644 index 000000000..3de855729 --- /dev/null +++ b/mpfr/sub1.c @@ -0,0 +1,406 @@ +/* mpfr_sub1 -- internal function to perform a "real" subtraction + +Copyright (C) 2001 Free Software Foundation. +Contributed by the Spaces project, INRIA Lorraine. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +/* signs of b and c differ, abs(b) > abs(c), + diff_exp = EXP(b) - EXP(c). + Returns 0 iff result is exact, + a negative value when the result is less than the exact value, + a positive value otherwise. +*/ + +int +mpfr_sub1 (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, + mp_rnd_t rnd_mode, mp_exp_unsigned_t diff_exp) +{ + unsigned long cancel, cancel1, sh, k; + long int cancel2, an, bn, cn, cn0; + mp_limb_t *ap, *bp, *cp, carry, bb, cc, borrow = 0; + int inexact = 0, shift_b, shift_c, is_exact = 1, down = 0, add_exp=0; + TMP_DECL(marker); + +#ifdef DEBUG + printf("\nenter mpfr_sub, rnd_mode=%s:\n", mpfr_print_rnd_mode(rnd_mode)); + printf("b="); if (MPFR_SIGN(b)>0) putchar(' '); mpfr_print_raw(b); putchar('\n'); + printf("c="); if (MPFR_SIGN(c)>0) putchar(' '); for (k=0; k<diff_exp; k++) putchar(' '); mpfr_print_raw(c); putchar('\n'); + printf("PREC(a)=%u PREC(b)=%u PREC(c)=%u\n", MPFR_PREC(a), MPFR_PREC(b), + MPFR_PREC(c)); +#endif + TMP_MARK(marker); + ap = MPFR_MANT(a); + an = 1 + (MPFR_PREC(a) - 1) / BITS_PER_MP_LIMB; + + cancel = mpfr_cmp2 (b, c); + + /* reserve a space to store b aligned with the result, i.e. shifted by + (-cancel) % BITS_PER_MP_LIMB to the right */ + bn = 1 + (MPFR_PREC(b) - 1) / BITS_PER_MP_LIMB; + shift_b = cancel % BITS_PER_MP_LIMB; + if (shift_b) + shift_b = BITS_PER_MP_LIMB - shift_b; + cancel1 = (cancel + shift_b) / BITS_PER_MP_LIMB; + /* the high cancel1 limbs from b should not be taken into account */ + if (shift_b == 0) + bp = MPFR_MANT(b); /* no need of an extra space */ + else + { + bp = TMP_ALLOC ((bn + 1) * BYTES_PER_MP_LIMB); + bp[0] = mpn_rshift (bp + 1, MPFR_MANT(b), bn++, shift_b); + } + + /* reserve a space to store c aligned with the result, i.e. shifted by + (diff_exp-cancel) % BITS_PER_MP_LIMB to the right */ + cn = 1 + (MPFR_PREC(c) - 1) / BITS_PER_MP_LIMB; + shift_c = diff_exp - (cancel % BITS_PER_MP_LIMB); + shift_c = (shift_c + BITS_PER_MP_LIMB) % BITS_PER_MP_LIMB; + if (shift_c == 0) + cp = MPFR_MANT(c); + else + { + cp = TMP_ALLOC ((cn + 1) * BYTES_PER_MP_LIMB); + cp[0] = mpn_rshift (cp + 1, MPFR_MANT(c), cn++, shift_c); + } + +#ifdef DEBUG + printf("shift_b=%u shift_c=%u\n", shift_b, shift_c); +#endif + + /* ensure ap != bp and ap != cp */ + if (ap == bp) + { + bp = (mp_ptr) TMP_ALLOC(bn * BYTES_PER_MP_LIMB); + MPN_COPY (bp, ap, bn); + /* ap == cp cannot occur since we would have b=c, which is detected + in mpfr_add or mpfr_sub */ + } + else if (ap == cp) + { + cp = (mp_ptr) TMP_ALLOC (cn * BYTES_PER_MP_LIMB); + MPN_COPY(cp, ap, cn); + } + + cancel2 = (long int) (cancel + shift_c - diff_exp) / BITS_PER_MP_LIMB; + /* the high cancel2 limbs from b should not be taken into account */ +#ifdef DEBUG + printf("cancel=%u cancel1=%u cancel2=%d\n", cancel, cancel1, cancel2); +#endif + + /* adjust sign of result */ + if (MPFR_SIGN(a)*MPFR_SIGN(b) < 0) + MPFR_CHANGE_SIGN(a); + + /* ap[an-1] ap[0] + <----------------+-----------|----> + <----------PREC(a)----------><-sh-> + cancel1 + limbs bp[bn-cancel1-1] + <--...-----><----------------+-----------+-----------> + cancel2 + limbs cp[cn-cancel2-1] cancel2 >= 0 + <--...--><----------------+----------------+----------------> + (-cancel2) cancel2 < 0 + limbs <----------------+----------------> + */ + + /* first part: put in ap[0..an-1] the value of high(b) - high(c), + where high(b) consists of the high an+cancel1 limbs of b, + and high(c) consists of the high an+cancel2 limbs of c. + */ + + /* copy high(b) into a */ + if (an + cancel1 <= bn) /* a: <----------------+-----------|----> + b: <-----------------------------------------> */ + MPN_COPY (ap, bp + bn - (an + cancel1), an); + else /* a: <----------------+-----------|----> + b: <-------------------------> */ + if (cancel1 < bn) /* otherwise b does not overlap with a */ + { + MPN_ZERO (ap, an + cancel1 - bn); + MPN_COPY (ap + an + cancel1 - bn, bp, bn - cancel1); + } + else + MPN_ZERO (ap, an); + +#ifdef DEBUG + printf("after copying high(b), a="); mpfr_print_raw(a); putchar('\n'); +#endif + + /* subtract high(c) */ + if (an + cancel2 > 0) /* otherwise c does not overlap with a */ + { + mp_limb_t *ap2; + + if (cancel2 >= 0) + { + if (an + cancel2 <= cn) /* a: <-----------------------------> + c: <-----------------------------------------> */ + mpn_sub_n (ap, ap, cp + cn - (an + cancel2), an); + else /* a: <----------------------------> + c: <-------------------------> */ + { + ap2 = ap + an + cancel2 - cn; + if (cn > cancel2) + mpn_sub_n (ap2, ap2, cp, cn - cancel2); + } + } + else /* cancel2 < 0 */ + { + if (an + cancel2 <= cn) /* a: <-----------------------------> + c: <-----------------------------> */ + borrow = mpn_sub_n (ap, ap, cp + cn - (an + cancel2), an + cancel2); + else /* a: <----------------------------> + c: <----------------> */ + { + ap2 = ap + an + cancel2 - cn; + borrow = mpn_sub_n (ap2, ap2, cp, cn); + } + ap2 = ap + an + cancel2; + mpn_sub_1 (ap2, ap2, -cancel2, borrow); + } + } + +#ifdef DEBUG + printf("after subtracting high(c), a="); mpfr_print_raw(a); putchar('\n'); +#endif + + /* now perform rounding */ + sh = an * BITS_PER_MP_LIMB - MPFR_PREC(a); /* last unused bits from a */ + carry = ap[0] & ((MP_LIMB_T_ONE << sh) - MP_LIMB_T_ONE); + ap[0] -= carry; + + if (rnd_mode == GMP_RNDN) + { + if (sh) + { + is_exact = (carry == 0); + /* can decide except when carry = 2^(sh-1) [middle] + or carry = 0 [truncate, but cannot decide inexact flag] */ + down = (carry < (MP_LIMB_T_ONE << (sh - 1))); + if (carry > (MP_LIMB_T_ONE << (sh - 1))) + goto add_one_ulp; + else if ((0 < carry) && down) + { + inexact = -1; /* result if smaller than exact value */ + goto truncate; + } + } + } + else /* directed rounding: set rnd_mode to RNDZ iff towards zero */ + { + if (((rnd_mode == GMP_RNDD) && (MPFR_SIGN(b) > 0)) || + ((rnd_mode == GMP_RNDU) && (MPFR_SIGN(b) < 0))) + rnd_mode = GMP_RNDZ; + + if (carry) + { + if (rnd_mode == GMP_RNDZ) + { + inexact = -1; + goto truncate; + } + else /* round away */ + goto add_one_ulp; + } + } + + /* we have to consider the low (bn - (an+cancel1)) limbs from b, + and the (cn - (an+cancel2)) limbs from c. */ + bn -= an + cancel1; + cn0 = cn; + cn -= (long int) an + cancel2; +#ifdef DEBUG + printf("last %u bits from a are %lu, bn=%ld, cn=%ld\n", sh, carry, bn, cn); +#endif + + for (k=0; (bn > 0) || (cn > 0); k++) + { + bb = (bn > 0) ? bp[--bn] : 0; + if ((cn > 0) && (cn-- <= cn0)) + cc = cp[cn]; + else + cc = 0; + +#ifdef DEBUG + printf("k=%u bb=%lu cc=%lu down=%d\n", k, bb, cc, down); +#endif + if (down == 0) + down = (bb < cc); + + if ((rnd_mode == GMP_RNDN) && !k && !sh) + { + mp_limb_t half = MP_LIMB_T_HIGHBIT; + + is_exact = (bb == cc); + + /* add one ulp if bb > cc + half + truncate if cc - half < bb < cc + half + sub one ulp if bb < cc - half + */ + + if (down) + { + if (cc >= half) + cc -= half; + else + bb += half; + } + else /* bb >= cc */ + { + if (cc < half) + cc += half; + else + bb -= half; + } + } + +#ifdef DEBUG + printf(" bb=%lu cc=%lu down=%d is_exact=%d\n", bb, cc, down, is_exact); +#endif + if (bb < cc) + { + if (rnd_mode == GMP_RNDZ) + goto sub_one_ulp; + else if (rnd_mode != GMP_RNDN) /* round away */ + { + inexact = 1; + goto truncate; + } + else /* round to nearest */ + { + if (is_exact && !sh) + { + inexact = 0; + goto truncate; + } + else if (down && !sh) + goto sub_one_ulp; + else + { + inexact = (is_exact) ? 1 : -1; + goto truncate; + } + } + } + else if (bb > cc) + { + if (rnd_mode == GMP_RNDZ) + { + inexact = -1; + goto truncate; + } + else if (rnd_mode != GMP_RNDN) /* round away */ + goto add_one_ulp; + else /* round to nearest */ + { + if (is_exact) + { + inexact = -1; + goto truncate; + } + else if (down) + { + inexact = 1; + goto truncate; + } + else + goto add_one_ulp; + } + } + } + + if ((rnd_mode == GMP_RNDN) && !is_exact) + { + /* even rounding rule */ + if ((ap[0] >> sh) & 1) + { + if (down) goto sub_one_ulp; + else goto add_one_ulp; + } + else + inexact = (down) ? 1 : -1; + } + else + inexact = 0; + goto truncate; + + sub_one_ulp: /* add one unit in last place to a */ + mpn_sub_1 (ap, ap, an, MP_LIMB_T_ONE << sh); + inexact = -1; + goto end_of_sub; + + add_one_ulp: /* add one unit in last place to a */ + if (mpn_add_1 (ap, ap, an, MP_LIMB_T_ONE << sh)) /* result is a power of 2 */ + { + ap[an-1] = MP_LIMB_T_HIGHBIT; + add_exp = 1; + } + inexact = 1; /* result larger than exact value */ + + truncate: + if ((ap[an-1] >> (BITS_PER_MP_LIMB - 1)) == 0) /* case 1 - epsilon */ + { + ap[an-1] = MP_LIMB_T_HIGHBIT; + add_exp = 1; + } + + end_of_sub: + /* we have to set MPFR_EXP(a) to MPFR_EXP(b) - cancel + add_exp, taking + care of underflows/overflows in that computation, and of the allowed + exponent range */ + if (cancel) + { + mp_exp_t exp_b; + + cancel -= add_exp; /* still valid as unsigned long */ + exp_b = MPFR_EXP(b); /* save it in case a equals b */ + MPFR_EXP(a) = MPFR_EXP(b) - cancel; + if ((MPFR_EXP(a) > exp_b) /* underflow in type mp_exp_t */ + || (MPFR_EXP(a) < __mpfr_emin)) + { + TMP_FREE(marker); + return mpfr_set_underflow (a, rnd_mode, MPFR_SIGN(a)); + } + } + else /* cancel = 0: MPFR_EXP(a) <- MPFR_EXP(b) + add_exp */ + { + /* in case cancel = 0, add_exp can still be 1, in case b is just + below a power of two, c is very small, prec(a) < prec(b), + and rnd=away or nearest */ + if (add_exp && MPFR_EXP(b) == __mpfr_emax) + { + TMP_FREE(marker); + return mpfr_set_overflow (a, rnd_mode, MPFR_SIGN(a)); + } + MPFR_EXP(a) = MPFR_EXP(b) + add_exp; + } + TMP_FREE(marker); +#ifdef DEBUG + printf ("result is a="); mpfr_print_raw(a); putchar('\n'); +#endif + /* check that result is msb-normalized */ + MPFR_ASSERTN(ap[an-1] > ~ap[an-1]); + return inexact * MPFR_SIGN(b); +} diff --git a/mpfr/sub_ui.c b/mpfr/sub_ui.c index 4b64caff7..cb18307d0 100644 --- a/mpfr/sub_ui.c +++ b/mpfr/sub_ui.c @@ -1,20 +1,20 @@ /* mpfr_sub_ui -- subtract a floating-point number and a machine integer -Copyright (C) 2000 Free Software Foundation. +Copyright (C) 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -26,29 +26,31 @@ MA 02111-1307, USA. */ #include "mpfr.h" #include "mpfr-impl.h" -void -#if __STDC__ +int 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_t uu; + mp_limb_t up[1]; + unsigned long cnt; + int inex_sub, inex_cr; - 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); + + /* Optimization note: Exponent operations may be removed + if mpfr_add works even when uu is out-of-range. */ + mpfr_save_emin_emax(); + inex_sub = mpfr_sub (y, x, uu, rnd_mode); + mpfr_restore_emin_emax(); + inex_cr = mpfr_check_range(y, rnd_mode); + if (inex_cr) + return inex_cr; /* underflow or overflow */ + MPFR_RET(inex_sub); } else - mpfr_set (y, x, rnd_mode); + return mpfr_set (y, x, rnd_mode); } diff --git a/mpfr/swap.c b/mpfr/swap.c index 18b6c981d..9dd7d4e27 100644 --- a/mpfr/swap.c +++ b/mpfr/swap.c @@ -1,21 +1,21 @@ /* mpfr_swap (U, V) -- Swap U and V. -Copyright (C) 1997, 1998, 2000 Free Software Foundation, Inc. +Copyright (C) 2000, 2001 Free Software Foundation, Inc. -This file is part of the GNU MP Library. +This file is part of the MPFR Library. -The GNU MP Library is free software; you can redistribute it and/or modify +The MPFR 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 +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 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 +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. */ @@ -24,13 +24,7 @@ MA 02111-1307, USA. */ #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; diff --git a/mpfr/tan.c b/mpfr/tan.c new file mode 100644 index 000000000..3effc8749 --- /dev/null +++ b/mpfr/tan.c @@ -0,0 +1,82 @@ +/* mpfr_tan -- tangent of a floating-point number + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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" + +/* computes tan(x) = sign(x)*sqrt(1/cos(x)^2-1) */ +int +mpfr_tan (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode) +{ + int precy, m, ok, e, inexact; + mpfr_t c; + + if (MPFR_IS_NAN(x) || MPFR_IS_INF(x)) + { + MPFR_SET_NAN(y); + return 1; /* inexact */ + } + + if (!MPFR_NOTZERO(x)) + { + mpfr_set_ui (y, 0, GMP_RNDN); + return 0; /* exact */ + } + + precy = MPFR_PREC(y); + m = precy + _mpfr_ceil_log2 ((double) precy) + ABS(MPFR_EXP(x)) + 13; + + mpfr_init2 (c, m); + + do + { + mpfr_cos (c, x, GMP_RNDZ); + mpfr_mul (c, c, c, GMP_RNDZ); + mpfr_ui_div (c, 1, c, GMP_RNDU); + e = MPFR_EXP(c); + mpfr_sub_ui (c, c, 1, GMP_RNDN); + e = e - MPFR_EXP(c); + mpfr_sqrt (c, c, GMP_RNDU); + if (mpfr_cmp_ui (x, 0) < 0) + mpfr_neg (c, c, GMP_RNDN); + + /* the error on c is at most (2+11*2^e)*ulp(c) <= 2^(e+4)*ulp(c) + = 2^(e+4+EXP(c)-m) = 2^(EXP(c)-err) */ + e = m - e - 4; + ok = (e >= 0) && mpfr_can_round (c, e, GMP_RNDN, rnd_mode, precy); + + if (ok == 0) + { + m += BITS_PER_MP_LIMB; + mpfr_set_prec (c, m); + } + } + while (!ok); + + inexact = mpfr_set (y, c, rnd_mode); + + mpfr_clear (c); + + return inexact; +} diff --git a/mpfr/tanh.c b/mpfr/tanh.c new file mode 100644 index 000000000..4f0baa5ec --- /dev/null +++ b/mpfr/tanh.c @@ -0,0 +1,150 @@ +/* mpfr_tanh -- hyperbolic tangent + +Copyright (C) 2001 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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + + /* The computation of cosh is done by + + tanh= [e^(x)^2-1]/+[e^(x)^2+1] + */ + +int +#if __STDC__ +mpfr_tanh (mpfr_ptr y, mpfr_srcptr xt , mp_rnd_t rnd_mode) +#else +mpfr_tanh (y, xt, rnd_mode) + mpfr_ptr y; + mpfr_srcptr xt; + mp_rnd_t rnd_mode; +#endif +{ + + /****** Declaration ******/ + mpfr_t x; + mp_prec_t Nxt = MPFR_PREC(xt); + int flag_neg=0, inexact=0; + + /* Special value checking */ + + if (MPFR_IS_NAN(xt)) + { + MPFR_SET_NAN(y); + return 1; + } + MPFR_CLEAR_NAN(y); + + if (MPFR_IS_INF(xt)) + { + if(MPFR_SIGN(xt) > 0) + return mpfr_set_si(y,1,rnd_mode); /* tanh(inf) = 1 */ + else + return mpfr_set_si(y,-1,rnd_mode); /* tanh(-inf) = -1 */ + } + MPFR_CLEAR_INF(y); + + /* tanh(0) = 0 */ + if(!MPFR_NOTZERO(xt)) + { + MPFR_SET_ZERO(y); + MPFR_SET_SAME_SIGN(y,xt); + return 0; + } + + mpfr_init2(x,Nxt); + mpfr_set(x,xt,GMP_RNDN); + + if(MPFR_SIGN(x)<0) + { + MPFR_CHANGE_SIGN(x); + flag_neg=1; + } + + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t t, te, ta,tb; + int d; + + /* Declaration of the size variable */ + mp_prec_t Nx = Nxt; /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ + + mp_prec_t Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt = Nt+_mpfr_ceil_log2(9)+_mpfr_ceil_log2(Nt); + + /* initialise of intermediary variable */ + mpfr_init(t); + mpfr_init(te); + mpfr_init(ta); + mpfr_init(tb); + + + /* First computation of cosh */ + do { + + /* reactualisation of the precision */ + mpfr_set_prec(t,Nt); + mpfr_set_prec(te,Nt); + mpfr_set_prec(ta,Nt); + mpfr_set_prec(tb,Nt); + + /* compute tanh */ + mpfr_mul_2exp(te,x,1,GMP_RNDN); /* 2x */ + mpfr_exp(te,te,GMP_RNDN); /* exp(2x) */ + mpfr_add_ui(ta,te,1,GMP_RNDD); /* exp(2x) + 1*/ + mpfr_sub_ui(tb,te,1,GMP_RNDU); /* exp(2x) - 1*/ + mpfr_div(t,tb,ta,GMP_RNDN); /* (exp(2x)-1)/(exp(2x)+1)*/ + + + /* calculation of the error*/ + d = MPFR_EXP(te)-MPFR_EXP(t); + + /* estimation of the error */ + /*err = Nt-(_mpfr_ceil_log2(7+pow(2,d+1)));*/ + err = Nt-(MAX(d+1,3)+1); + + /* actualisation of the precision */ + Nt += 10; + + } while ((err <0)||!mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny)); + + if (flag_neg==1) + MPFR_CHANGE_SIGN(t); + + inexact = mpfr_set(y,t,rnd_mode); + mpfr_clear(t); + mpfr_clear(te); + mpfr_clear(ta); + mpfr_clear(tb); + } + mpfr_clear(x); + return inexact; + +} + diff --git a/mpfr/trunc.c b/mpfr/trunc.c index a40bf8e89..63af13808 100644 --- a/mpfr/trunc.c +++ b/mpfr/trunc.c @@ -1,22 +1,22 @@ /* 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. +Copyright (C) 1999, 2001 Free Software Foundation, Inc. -This file is part of the GNU MP Library. +This file is part of the MPFR 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 +The MPFR 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 +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 +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 Library General Public License -along with the GNU MP Library; see the file COPYING.LIB. If not, write to +You should have received a copy of the GNU Lesser 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. */ @@ -26,21 +26,27 @@ MA 02111-1307, USA. */ #include "mpfr.h" #include "mpfr-impl.h" -#ifdef OPERATION_floor +#if ! defined (MPFR_FLOOR) && ! defined (MPFR_CEIL) +#define MPFR_TRUNC 1 +#endif + +#if MPFR_FLOOR #define _MPFR_FLOOR_OR_CEIL #define FUNC_NAME mpfr_floor +#undef MPFR_FLOOR #define MPFR_FLOOR 1 #define MPFR_CEIL 0 #endif -#ifdef OPERATION_ceil +#if MPFR_CEIL #define _MPFR_FLOOR_OR_CEIL #define FUNC_NAME mpfr_ceil +#undef MPFR_CEIL #define MPFR_CEIL 1 #define MPFR_FLOOR 0 #endif -#ifdef OPERATION_trunc +#if MPFR_TRUNC #undef FUNC_NAME #define FUNC_NAME mpfr_trunc #endif @@ -64,17 +70,11 @@ mpn_zero_p (p, n) #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; + mp_size_t usize; + mp_size_t rsize, rw; #ifdef _MPFR_FLOOR_OR_CEIL mp_size_t ignored_n; #endif @@ -104,7 +104,7 @@ FUNC_NAME (r, u) signu = MPFR_SIZE(u); rp = MPFR_MANT(r); exp = MPFR_EXP(u); - prec = (MPFR_PREC(r) - 1)/BITS_PER_MP_LIMB + 1; + rsize = (MPFR_PREC(r) - 1)/BITS_PER_MP_LIMB + 1; /* Single out the case where |u| < 1. */ if (exp <= 0) @@ -112,8 +112,8 @@ FUNC_NAME (r, u) #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); + rp[rsize-1] = MP_LIMB_T_HIGHBIT; + MPN_ZERO(rp, rsize-1); /* sign of result is that of u */ if (MPFR_SIGN(r) * signu < 0) MPFR_CHANGE_SIGN(r); MPFR_EXP(r) = 1; @@ -124,23 +124,23 @@ FUNC_NAME (r, u) return; } - asize = (MPFR_PREC(u) - 1)/BITS_PER_MP_LIMB + 1; + usize = (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) + if (usize > rsize) { #ifdef _MPFR_FLOOR_OR_CEIL - ignored_n = asize - prec; + ignored_n = usize - rsize; #endif - up += asize - prec; - asize = prec; + up += usize - rsize; + usize = rsize; } - diff = BITS_PER_MP_LIMB * asize - exp; + diff = BITS_PER_MP_LIMB * usize - exp; if (diff > 0) { diff = diff/BITS_PER_MP_LIMB; @@ -148,13 +148,13 @@ FUNC_NAME (r, u) ignored_n += diff; #endif up += diff; - asize -= diff; + usize -= 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; + rw = usize * BITS_PER_MP_LIMB - exp; + MPN_ZERO(rp, rsize-usize); + rp += rsize-usize; #ifdef _MPFR_FLOOR_OR_CEIL if (((MPFR_FLOOR && signu < 0) || (MPFR_CEIL && signu >= 0)) @@ -162,21 +162,24 @@ FUNC_NAME (r, u) || (rw && (up[0] << (BITS_PER_MP_LIMB-rw))))) { mp_limb_t cy; - cy = mpn_add_1 (rp, up, asize, (mp_limb_t) 1 << rw); + cy = mpn_add_1 (rp, up, usize, MP_LIMB_T_ONE << rw); if (cy != 0) { - mpn_rshift(rp, rp, asize, 1); - rp[asize-1] = (mp_limb_t) 1 << (BITS_PER_MP_LIMB - 1); + /* all the bits from "1<<rw" upwards are zero */ + rp[usize-1] = MP_LIMB_T_HIGHBIT; exp++; } } else #endif - MPN_COPY (rp, up, asize); + { + if (rp != up) + MPN_COPY (rp, up, usize); + } /* Put to 0 the remaining bits */ if (rw) rp[0] &= - ~((((mp_limb_t)1)<<rw) - (mp_limb_t)1); + ~((MP_LIMB_T_ONE << rw) - MP_LIMB_T_ONE); 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 index 712d00dd9..d55f98d6f 100644 --- a/mpfr/ui_div.c +++ b/mpfr/ui_div.c @@ -1,20 +1,20 @@ /* mpfr_ui_div -- divide a machine integer by a floating-point number -Copyright (C) 2000 Free Software Foundation. +Copyright (C) 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -26,16 +26,8 @@ MA 02111-1307, USA. */ #include "mpfr.h" #include "mpfr-impl.h" -void -#if __STDC__ +int 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]; @@ -44,31 +36,42 @@ mpfr_ui_div (y, u, x, rnd_mode) if (MPFR_IS_NAN(x)) { MPFR_SET_NAN(y); - return; + MPFR_RET_NAN; } MPFR_CLEAR_NAN(y); - if (MPFR_IS_INF(x)) + if (MPFR_IS_INF(x)) /* u/Inf = 0 */ { MPFR_CLEAR_INF(y); MPFR_SET_ZERO(y); - if (MPFR_SIGN(x) != MPFR_SIGN(y)) MPFR_CHANGE_SIGN(y); - return; + if (MPFR_SIGN(x) != MPFR_SIGN(y)) + MPFR_CHANGE_SIGN(y); + MPFR_RET(0); } 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; + 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 */ - } + return mpfr_div (y, uu, x, rnd_mode); + } + else /* u = 0 */ + { + if (MPFR_IS_ZERO(x)) /* 0/0 */ + { + MPFR_SET_NAN(y); + MPFR_RET_NAN; + } + else + { + MPFR_SET_ZERO(y); /* if u=0, then set y to 0 */ + MPFR_RET(0); + } + } } diff --git a/mpfr/ui_pow.c b/mpfr/ui_pow.c new file mode 100644 index 000000000..ac3cb52dd --- /dev/null +++ b/mpfr/ui_pow.c @@ -0,0 +1,119 @@ +/* mpfr_ui_pow -- power of n function n^x + +Copyright (C) 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" + + + /* The computation of y=pow(n,z) is done by + + y=exp(z*log(n))=n^z + */ + +int +mpfr_ui_pow (mpfr_ptr y, unsigned long int n,mpfr_srcptr x, mp_rnd_t rnd_mode) +{ + int inexact; + + 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_ZERO(y); + if (MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN(y); + return 0; + } + else + { + MPFR_SET_INF(y); + if(MPFR_SIGN(y) < 0) + MPFR_CHANGE_SIGN(y); + return 0; + } + } + + /* n^0 = 1 */ + if(mpfr_cmp_ui(x,0)==0) + { + return mpfr_set_ui(y,1,rnd_mode); + } + + /* General case */ + { + /* Declaration of the intermediary variable */ + mpfr_t t, te, ti; + + /* Declaration of the size variable */ + mp_prec_t Nx = MPFR_PREC(x); /* Precision of input variable */ + mp_prec_t Ny = MPFR_PREC(y); /* Precision of input variable */ + + mp_prec_t Nt; /* Precision of the intermediary variable */ + long int err; /* Precision of error */ + + /* compute the precision of intermediary variable */ + Nt=MAX(Nx,Ny); + /* the optimal number of bits : see algorithms.ps */ + Nt=Nt+5+_mpfr_ceil_log2(Nt); + + /* initialise of intermediary variable */ + mpfr_init(t); + mpfr_init2(ti,sizeof(unsigned long int)*8); /* 8 = CHAR_BIT */ + mpfr_init(te); + + do { + + /* reactualisation of the precision */ + mpfr_set_prec(t,Nt); + mpfr_set_prec(te,Nt); + + /* compute exp(x*ln(n))*/ + mpfr_set_ui(ti,n,GMP_RNDN); /* ti <- n*/ + mpfr_log(t,ti,GMP_RNDU); /* ln(n) */ + mpfr_mul(te,x,t,GMP_RNDU); /* x*ln(n) */ + mpfr_exp(t,te,GMP_RNDN); /* exp(x*ln(n))*/ + + /* estimation of the error -- see pow function in algorithms.ps*/ + err = Nt - (MPFR_EXP(te)+3); + + /* actualisation of the precision */ + Nt += 10; + + } while (err<0 || !mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny)); + + inexact = mpfr_set(y,t,rnd_mode); + mpfr_clear(t); + mpfr_clear(ti); + mpfr_clear(te); + } + return inexact; + +} diff --git a/mpfr/ui_pow_ui.c b/mpfr/ui_pow_ui.c new file mode 100644 index 000000000..494d7c44d --- /dev/null +++ b/mpfr/ui_pow_ui.c @@ -0,0 +1,80 @@ +/* mpfr_ui_pow_ui -- compute the power beetween two machine integer + +Copyright (C) 1999, 2001 Free Software Foundation, Inc. + +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 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 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser 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 "mpfr.h" +#include "mpfr-impl.h" + + +int +mpfr_ui_pow_ui (mpfr_ptr x, unsigned long int y, unsigned long int n, + mp_rnd_t rnd) +{ + long int i, err; + unsigned long m; + mpfr_t res; + mp_prec_t prec; + int inexact; + + MPFR_CLEAR_FLAGS(x); + + if (n == 0) /* x^0 = 1 for any x */ + { + mpfr_set_ui (x, 1, rnd); + return 0; + } + + mpfr_init (res); + + prec = MPFR_PREC(x); + + do + { + prec += 3; + for (m=n, i=0; m; i++, m>>=1, prec++); + mpfr_set_prec (res, prec); + inexact = mpfr_set_ui (res, y, GMP_RNDU); + err = 1; + /* now 2^(i-1) <= n < 2^i */ + for (i-=2; i>=0; i--) + { + if (mpfr_mul (res, res, res, GMP_RNDU)) + inexact = 1; + err++; + if (n & (1 << i)) + if (mpfr_mul_ui (res, res, y, GMP_RNDU)) + inexact = 1; + } + err = prec - err; + if (err < 0) + err = 0; + } + while (inexact && (mpfr_can_round (res, err, + (MPFR_SIGN(res) > 0) ? GMP_RNDU : GMP_RNDD, rnd, MPFR_PREC(x)) == 0)); + + if (mpfr_set (x, res, rnd)) + inexact = 1; + + mpfr_clear (res); + + return inexact; +} diff --git a/mpfr/ui_sub.c b/mpfr/ui_sub.c index 8bc560cd6..144a9b942 100644 --- a/mpfr/ui_sub.c +++ b/mpfr/ui_sub.c @@ -1,20 +1,20 @@ /* mpfr_ui_sub -- divide a machine integer by a floating-point number -Copyright (C) 2000 Free Software Foundation. +Copyright (C) 2000, 2001 Free Software Foundation, Inc. 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 +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 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 +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 Library General Public License +You should have received a copy of the GNU Lesser 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. */ @@ -26,25 +26,17 @@ MA 02111-1307, USA. */ #include "mpfr.h" #include "mpfr-impl.h" -void -#if __STDC__ +int 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; + return 1; /* a NaN is inexact */ } MPFR_CLEAR_NAN(y); @@ -52,17 +44,19 @@ mpfr_ui_sub (y, u, x, rnd_mode) if (MPFR_IS_INF(x)) { MPFR_SET_INF(y); - if (MPFR_SIGN(x) == MPFR_SIGN(y)) MPFR_CHANGE_SIGN(y); - return; + if (MPFR_SIGN(x) == MPFR_SIGN(y)) + MPFR_CHANGE_SIGN(y); + return 0; /* +/-infinity is exact */ } if (u) { - MPFR_INIT1(up, uu, BITS_PER_MP_LIMB, 1); - count_leading_zeros(cnt, (mp_limb_t) 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_EXP(uu) = BITS_PER_MP_LIMB - cnt; - mpfr_sub (y, uu, x, rnd_mode); + return mpfr_sub (y, uu, x, rnd_mode); } - else mpfr_neg (y, x, rnd_mode); /* if u=0, then set y to -x */ + else + return mpfr_neg (y, x, rnd_mode); /* if u=0, then set y to -x */ } diff --git a/mpfr/urandomb.c b/mpfr/urandomb.c index 02d909824..0ffdf156f 100644 --- a/mpfr/urandomb.c +++ b/mpfr/urandomb.c @@ -3,22 +3,22 @@ using STATE as the random state previously initialized by a call to gmp_randinit(). -Copyright (C) 1999, 2000 Free Software Foundation, Inc. +Copyright (C) 2000, 2001 Free Software Foundation, Inc. -This file is part of the GNU MP Library. +This file is part of the MPFR 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 +The MPFR 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 +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 +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 Library General Public License -along with the GNU MP Library; see the file COPYING.LIB. If not, write to +You should have received a copy of the GNU Lesser 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. */ @@ -30,13 +30,7 @@ MA 02111-1307, USA. */ #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; @@ -72,7 +66,7 @@ mpfr_urandomb (rop, rstate) 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); + rp[0] &= ~((MP_LIMB_T_ONE << cnt) - 1); MPFR_EXP (rop) = exp; } |