#include #include "gmp.h" #include "gmp-impl.h" #include "mpfr.h" /* #define DEBUG2 */ #ifdef DEBUG2 mp_limb_t *ap0, *ap1; #define ck(x, dx, i) /* mp_limb_t *x; int dx; */ \ { \ if ((x)ap1) { \ printf("error %d\n",(i)); \ printf("%1.20e,%d,%1.20e,%d,%d,%d\n",mpfr_get_d(b),PREC(b),mpfr_get_d(c), \ PREC(c),PREC(a),rnd_mode); \ exit(1); } \ } #else #define ck(x, dx, i) {} #endif void mpfr_sub(a, b, c, rnd_mode) mpfr_ptr a; mpfr_srcptr b, c; unsigned char rnd_mode; { CHANGE_SIGN(c); mpfr_add(a, b, c, rnd_mode); CHANGE_SIGN(c); } /* put in ap[0]..ap[an-1] the value of bp[0]..bp[n-1] shifted by sh bits to the left minus ap[0]..ap[n-1], with 0 <= sh < mp_bits_per_limb, and returns the borrow. */ mp_limb_t mpn_sub_lshift_n (ap, bp, n, sh, an) mp_limb_t *ap, *bp; int n,sh,an; { mp_limb_t c, bh; /* shift b to the left */ if (sh) bh = mpn_lshift(bp, bp, n, sh); c = (n=abs(c), diff_exp>=0 */ void mpfr_sub1(a, b, c, rnd_mode, diff_exp) mpfr_t a, b, c; unsigned char rnd_mode; int diff_exp; { mp_limb_t *ap, *bp, *cp, cc, c2; unsigned int an,bn,cn; int sh,dif,k,cancel,cancel1,cancel2; #ifdef DEBUG2 printf("b= "); if (SIGN(b)>=0) putchar(' '); mpfr_print_raw(b); putchar('\n'); printf("c= "); if (SIGN(c)>=0) putchar(' '); for (k=0;k=prec(a), i.e. c only affects the last bit through rounding */ dif = PREC(a)-diff_exp; #ifdef DEBUG2 printf("PREC(a)=%d an=%u PREC(b)=%d bn=%u PREC(c)=%d diff_exp=%u dif=%d\n", PREC(a),an,PREC(b),bn,PREC(c),diff_exp,dif); #endif if (dif<=0) { /* diff_exp>=PREC(a): c does not overlap with a */ /* either PREC(b)<=PREC(a), and we can copy the mantissa of b directly into that of a, or PREC(b)>PREC(a) and we have to round b-c */ if (PREC(b)<=PREC(a)+cancel) { if (cancel2) { ck(ap+(an-bn+cancel1), bn-cancel1, 1); mpn_lshift(ap+(an-bn+cancel1), bp, bn-cancel1, cancel2); } else { ck(ap+(an-bn+cancel1), bn-cancel1, 2); MPN_COPY(ap+(an-bn+cancel1), bp, bn-cancel1); } /* fill low significant limbs with zero */ ck(ap, an-bn+cancel1, 3); MPN_ZERO(ap, an-bn+cancel1); /* now take c into account */ if (rnd_mode==GMP_RNDN) { /* to nearest */ /* if diff_exp > PREC(a), no change */ if (diff_exp==PREC(a)) { /* if c is not zero, then as it is normalized, we have to subtract one to the lsb of a if c>1/2, or c=1/2 and lsb(a)=1 (round to even) */ if (NOTZERO(c)) { /* c is not zero */ /* check whether mant(c)=1/2 or not */ cc = *cp - (1<<(mp_bits_per_limb-1)); if (cc==0) { bp = cp+(PREC(c)-1)/mp_bits_per_limb; while (cp 1/2 or mant(c) = 1/2: subtract 1 iff lsb(a)=1 */ } } } else if ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || (ISNEG(b) && rnd_mode==GMP_RNDD)) { /* round up: nothing to do */ } else { /* round down: subtract 1 ulp iff c<>0 */ if (NOTZERO(c)) goto sub_one_ulp; } } else { /* PREC(b)>PREC(a) : we have to round b-c */ k=bn-an; /* first copy the 'an' most significant limbs of b to a */ ck(ap, an, 5); MPN_COPY(ap, bp+k, an); if (rnd_mode==GMP_RNDN) { /* to nearest */ /* first check whether the truncated bits from b are 1/2*lsb(a) */ if (sh) { ck(ap, 1, 6); cc = *ap & (((mp_limb_t)1<0) { /* suppose sizeof(long)=sizeof(mp_limb_t) */ goto add_one_ulp; /* trunc(b)>1/2*lsb(a) -> round up */ } else if (cc==0) { while (k>1 && cc==0) cc=bp[--k]; /* now if the truncated part of b = 1/2*lsb(a), check whether c=0 */ ck(ap, 1, 7); if (NOTZERO(c) || (*ap & (1< round down, i.e. do nothing */ } else { /* round towards infinity or zero */ if (sh) { ck(ap, 1, 8); cc = *ap & ((1<-sh) ? cp[cn]>>(mp_bits_per_limb-dif-sh) : 0; while (cc==c2 && (k || cn)) { if (k) cc = bp[--k]; if (cn) { c2 = cp[cn]<<(dif+sh); if (--cn) c2 += cp[cn]>>(mp_bits_per_limb-dif-sh); } } dif = ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || (ISNEG(b) && rnd_mode==GMP_RNDD)); /* round towards infinity if dif=1, towards zero otherwise */ if (dif && cc>c2) goto add_one_ulp; else if (dif==0 && cc0) { ck(ap, (k<=an) ? k : an, 10); mpn_rshift(ap, cp+(cn-k), (k<=an) ? k : an, dif); if (k>an) ap[an-1] += cp[cn-k+an]<<(mp_bits_per_limb-dif); } else if (dif<0) { ck(ap, k, 11); cc = mpn_lshift(ap, cp+(cn-k), k, -dif); if (k>(mp_bits_per_limb+dif); } else { ck(ap, k, 13); MPN_COPY(ap, cp+(cn-k), k); } overlap=1; } else { /* c is not truncated, but we have to fill low limbs with 0 */ ck(ap, k-cn, 14); MPN_ZERO(ap, k-cn); overlap = cancel-diff_exp; #ifdef DEBUG2 printf("0:a="); mpfr_print_raw(a); putchar('\n'); printf("overlap=%d\n",overlap); #endif if (overlap>=0) { cn -= overlap/mp_bits_per_limb; /* warning: a shift of zero with mpn_lshift is not allowed */ if (overlap) { if (an>(mp_bits_per_limb-overlap); } else { ck(ap+(an-cn), cn, 15); mpn_lshift(ap+(an-cn), cp, cn, overlap%mp_bits_per_limb); } } else { ck(ap+(an-cn), cn, 15); MPN_COPY(ap+(an-cn), cp, cn); } } else { /* shift to the right by -overlap bits */ overlap = -overlap; k = overlap/mp_bits_per_limb; cc=mpn_rshift(ap+(an-k-cn),cp,cn,overlap%mp_bits_per_limb); if (an>k+cn) ap[an-k-cn-1]=cc; } overlap=0; } #ifdef DEBUG2 printf("1:a="); mpfr_print_raw(a); putchar('\n'); #endif /* here overlap=1 iff ulp(c) PREC(a): we have to truncate b */ ck(ap, an, 21); mpn_sub_lshift_n(ap, bp+(bn-an-cancel1), an, cancel2, an); } /* remains to do the rounding */ #ifdef DEBUG2 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) PREC(b) > PREC(a) and diff_exp+PREC(c) <= PREC(a) (1) PREC(b) > PREC(a) and diff_exp+PREC(c) > PREC(a) (2) PREC(b) <= PREC(a) and diff_exp+PREC(c) <= PREC(a) (3) PREC(b) <= PREC(a) and diff_exp+PREC(c) > PREC(a) */ switch (overlap) { case 1: /* both b and c to round */ kc = cn-k; /* remains kc limbs from c */ k = bn-an; /* remains k limbs from b */ /* truncate last bits and store the difference with 1/2*ulp in cc */ cc = *ap & ((1<>dif) + (cp[kc+1]<<(mp_bits_per_limb-dif))); if (cc==0 || cc==-1) cc=c2; } if ((long)cc>0) goto add_one_ulp; else if ((long)cc<-1) return; /* the carry can be at most 1 */ else if (kc==0) goto round_b; /* else round c: go through */ case 3: /* only c to round */ bp=cp; k=cn-k; goto to_nearest; case 0: /* only b to round */ round_b: k=bn-an; dif=0; goto to_nearest; /* otherwise the result is exact: nothing to do */ } } else if ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || (ISNEG(b) && rnd_mode==GMP_RNDD)) { cc = *ap & ((1<>dif); if (dif) cc -= (cp[kc+1]<<(mp_bits_per_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]<<(mp_bits_per_limb-dif))) goto add_one_ulp; */ break; case 0: /* only b to round */ round_b2: k=bn-an; while (k) if (bp[--k]) goto add_one_ulp; /* otherwise the result is exact: nothing to do */ } } } /* else round to zero: remove 1 ulp if neglected bits from b-c are < 0 */ else { cc = *ap & ((1< no borrow */ case 1: /* both b and c are truncated */ break; case 3: /* only c is truncated */ cn -= k; /* take into account cp[0]..cp[cn-1] shifted by dif bits to the right */ cc = (dif>0) ? cp[cn]<<(mp_bits_per_limb-dif) : 0; while (cc==0 && cn>0) cc = cp[--cn]; if (cc) goto sub_one_ulp; break; } } } } goto end_of_sub; to_nearest: /* 0 <= sh < mp_bits_per_limb : number of bits of a to truncate bp[k] : last significant limb from b */ #ifdef DEBUG2 mpfr_print_raw(a); putchar('\n'); #endif if (sh) { cc = *ap & ((1<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 DEBUG2 printf("cc=%lu\n",cc); #endif /* special case of rouding c shifted to the right */ if (cc==0 && dif>0) cc=bp[0]<<(mp_bits_per_limb-dif); /* now if the truncated part of b = 1/2*lsb(a), check whether c=0 */ if (bp!=cp) { if (cc || (*ap & (1<0, do nothing */ if (cc==0 && (*ap & (1<