summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Ryde <user42@zip.com.au>2001-11-30 01:39:14 +0100
committerKevin Ryde <user42@zip.com.au>2001-11-30 01:39:14 +0100
commita30a00c444bb3d2b90c14b488c66fafa7df3c631 (patch)
tree8a7ce3e110086e9371072f0c8a7e5151f60f290b
parent1778ba984df3d10a3a95e58ce8990fa0b431c3a3 (diff)
downloadgmp-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.c134
-rw-r--r--mpfr/add.c506
-rw-r--r--mpfr/add1.c548
-rw-r--r--mpfr/add_ui.c57
-rw-r--r--mpfr/add_ulp.c55
-rw-r--r--mpfr/agm.c83
-rw-r--r--mpfr/asin.c181
-rw-r--r--mpfr/asinh.c136
-rw-r--r--mpfr/atan.c261
-rw-r--r--mpfr/atanh.c142
-rw-r--r--mpfr/ceil.c2
-rw-r--r--mpfr/clear.c15
-rw-r--r--mpfr/cmp.c255
-rw-r--r--mpfr/cmp2.c183
-rw-r--r--mpfr/cmp_abs.c72
-rw-r--r--mpfr/cmp_ui.c33
-rw-r--r--mpfr/copysign.c76
-rw-r--r--mpfr/cos.c137
-rw-r--r--mpfr/cosh.c126
-rw-r--r--mpfr/dim.c55
-rw-r--r--mpfr/div.c602
-rw-r--r--mpfr/div_2exp.c29
-rw-r--r--mpfr/div_ui.c203
-rw-r--r--mpfr/dump.c32
-rw-r--r--mpfr/eq.c28
-rw-r--r--mpfr/euler.c171
-rw-r--r--mpfr/exceptions.c230
-rw-r--r--mpfr/exp.c119
-rw-r--r--mpfr/exp2.c465
-rw-r--r--mpfr/exp3.c94
-rw-r--r--mpfr/exp_2.c368
-rw-r--r--mpfr/expm1.c116
-rw-r--r--mpfr/extract.c17
-rw-r--r--mpfr/factorial.c104
-rw-r--r--mpfr/floor.c2
-rw-r--r--mpfr/fma.c200
-rw-r--r--mpfr/generic.c89
-rw-r--r--mpfr/get_str.c70
-rw-r--r--mpfr/gmp_op.c122
-rw-r--r--mpfr/hypot.c134
-rw-r--r--mpfr/init.c43
-rw-r--r--mpfr/init2.c46
-rw-r--r--mpfr/inp_str.c22
-rw-r--r--mpfr/isinf.c31
-rw-r--r--mpfr/isinteger.c49
-rw-r--r--mpfr/isnan.c22
-rw-r--r--mpfr/isnum.c31
-rw-r--r--mpfr/log.c72
-rw-r--r--mpfr/log1p.c134
-rw-r--r--mpfr/log2.c100
-rw-r--r--mpfr/log_base_10.c147
-rw-r--r--mpfr/log_base_2.c151
-rw-r--r--mpfr/minmax.c81
-rw-r--r--mpfr/mpz_set_fr.c38
-rw-r--r--mpfr/mul.c134
-rw-r--r--mpfr/mul_2exp.c31
-rw-r--r--mpfr/mul_ui.c136
-rw-r--r--mpfr/neg.c31
-rw-r--r--mpfr/out_str.c68
-rw-r--r--mpfr/pi.c31
-rw-r--r--mpfr/pow.c321
-rw-r--r--mpfr/pow_si.c160
-rw-r--r--mpfr/pow_ui.c106
-rw-r--r--mpfr/print_raw.c31
-rw-r--r--mpfr/print_rnd_mode.c36
-rw-r--r--mpfr/random.c27
-rw-r--r--mpfr/random2.c28
-rw-r--r--mpfr/reldiff.c46
-rw-r--r--mpfr/rnd_mode.c17
-rw-r--r--mpfr/round.c507
-rw-r--r--mpfr/save_expo.c62
-rw-r--r--mpfr/set.c83
-rw-r--r--mpfr/set_d.c164
-rw-r--r--mpfr/set_dfl_prec.c15
-rw-r--r--mpfr/set_f.c67
-rw-r--r--mpfr/set_prc_raw.c17
-rw-r--r--mpfr/set_prec.c31
-rw-r--r--mpfr/set_q.c52
-rw-r--r--mpfr/set_rnd.c15
-rw-r--r--mpfr/set_si.c72
-rw-r--r--mpfr/set_str.c38
-rw-r--r--mpfr/set_str_raw.c26
-rw-r--r--mpfr/set_ui.c85
-rw-r--r--mpfr/set_z.c29
-rw-r--r--mpfr/sin.c78
-rw-r--r--mpfr/sinh.c135
-rw-r--r--mpfr/sqrt.c123
-rw-r--r--mpfr/sqrt_ui.c54
-rw-r--r--mpfr/sub.c672
-rw-r--r--mpfr/sub1.c406
-rw-r--r--mpfr/sub_ui.c44
-rw-r--r--mpfr/swap.c16
-rw-r--r--mpfr/tan.c82
-rw-r--r--mpfr/tanh.c150
-rw-r--r--mpfr/trunc.c79
-rw-r--r--mpfr/ui_div.c61
-rw-r--r--mpfr/ui_pow.c119
-rw-r--r--mpfr/ui_pow_ui.c80
-rw-r--r--mpfr/ui_sub.c40
-rw-r--r--mpfr/urandomb.c26
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;
diff --git a/mpfr/eq.c b/mpfr/eq.c
index 95b04a986..792728ad0 100644
--- a/mpfr/eq.c
+++ b/mpfr/eq.c
@@ -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;
}
diff --git a/mpfr/pi.c b/mpfr/pi.c
index fa72a5f8c..94ea9fb3c 100644
--- a/mpfr/pi.c
+++ b/mpfr/pi.c
@@ -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;
}