/* mpfr_sub -- subtract two floating-point numbers Copyright (C) 1999 Free Software Foundation. This file is part of the MPFR Library. The MPFR Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The MPFR Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the MPFR Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" /* #define DEBUG */ #define ONE ((mp_limb_t) 1) extern void mpfr_add1 _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 { mp_limb_t c, bh=0; /* shift b to the left */ if (sh) bh = mpn_lshift(bp, bp, n, sh); c = (n=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); #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=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 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; } } 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<0) { cn--; c2old = cp[cn]; /* last limb from c considered */ cout -= mpn_sub_1(&cc, &cc, 1, c2old >> (BITS_PER_MP_LIMB-dif)); } else c2 = c2old = 0; 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 */ 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; if (MPFR_ISNEG(b)) sign=-sign; /* even rounding rule: */ if (rnd_mode==GMP_RNDN && cout==0 && (*ap & (ONE<0) goto add_one_ulp; else if ((sign==-1) && cout<0) goto sub_one_ulp; } } } 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 (k0) { 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= 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=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>(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) (int)an) imax = an; for (i=0;i 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< 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<>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< 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]>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; } } } } 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<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<0, do nothing */ if (cc==0 && (*ap & (ONE<