int mpfr_sub1sp (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode) { mpfr_exp_t bx,cx; mpfr_uexp_t d; mpfr_prec_t p, sh, cnt; mp_size_t n; mp_limb_t *ap, *bp, *cp; mp_limb_t limb; int inexact; mp_limb_t bcp,bcp1; /* Cp and C'p+1 */ mp_limb_t bbcp = (mp_limb_t) -1, bbcp1 = (mp_limb_t) -1; /* Cp+1 and C'p+2, gcc claims that they might be used uninitialized. We fill them with invalid values, which should produce a failure if so. See README.dev file. */ MPFR_TMP_DECL(marker); MPFR_TMP_MARK(marker); MPFR_ASSERTD(MPFR_PREC(a) == MPFR_PREC(b) && MPFR_PREC(b) == MPFR_PREC(c)); MPFR_ASSERTD(MPFR_IS_PURE_FP(b)); MPFR_ASSERTD(MPFR_IS_PURE_FP(c)); /* Read prec and num of limbs */ p = MPFR_PREC (b); n = MPFR_PREC2LIMBS (p); /* Fast cmp of |b| and |c|*/ bx = MPFR_GET_EXP (b); cx = MPFR_GET_EXP (c); if (MPFR_UNLIKELY(bx == cx)) { mp_size_t k = n - 1; /* Check mantissa since exponent are equals */ bp = MPFR_MANT(b); cp = MPFR_MANT(c); while (k>=0 && MPFR_UNLIKELY(bp[k] == cp[k])) k--; if (MPFR_UNLIKELY(k < 0)) /* b == c ! */ { /* Return exact number 0 */ if (rnd_mode == MPFR_RNDD) MPFR_SET_NEG(a); else MPFR_SET_POS(a); MPFR_SET_ZERO(a); MPFR_RET(0); } else if (bp[k] > cp[k]) goto BGreater; else { MPFR_ASSERTD(bp[k]<cp[k]); goto CGreater; } } else if (MPFR_UNLIKELY(bx < cx)) { /* Swap b and c and set sign */ mpfr_srcptr t; mpfr_exp_t tx; CGreater: MPFR_SET_OPPOSITE_SIGN(a,b); t = b; b = c; c = t; tx = bx; bx = cx; cx = tx; } else { /* b > c */ BGreater: MPFR_SET_SAME_SIGN(a,b); } /* Now b > c */ MPFR_ASSERTD(bx >= cx); d = (mpfr_uexp_t) bx - cx; DEBUG (printf ("New with diff=%lu\n", (unsigned long) d)); if (MPFR_UNLIKELY(d <= 1)) { if (MPFR_LIKELY(d < 1)) { /* <-- b --> <-- c --> : exact sub */ ap = MPFR_MANT(a); mpn_sub_n (ap, MPFR_MANT(b), MPFR_MANT(c), n); /* Normalize */ ExactNormalize: limb = ap[n-1]; if (MPFR_LIKELY(limb)) { /* First limb is not zero. */ count_leading_zeros(cnt, limb); /* cnt could be == 0 <= SubD1Lose */ if (MPFR_LIKELY(cnt)) { mpn_lshift(ap, ap, n, cnt); /* Normalize number */ bx -= cnt; /* Update final expo */ } /* Last limb should be ok */ MPFR_ASSERTD(!(ap[0] & MPFR_LIMB_MASK((unsigned int) (-p) % GMP_NUMB_BITS))); } else { /* First limb is zero */ mp_size_t k = n-1, len; /* Find the first limb not equal to zero. FIXME:It is assume it exists (since |b| > |c| and same prec)*/ do { MPFR_ASSERTD( k > 0 ); limb = ap[--k]; } while (limb == 0); MPFR_ASSERTD(limb != 0); count_leading_zeros(cnt, limb); k++; len = n - k; /* Number of last limb */ MPFR_ASSERTD(k >= 0); if (MPFR_LIKELY(cnt)) mpn_lshift(ap+len, ap, k, cnt); /* Normalize the High Limb*/ else { /* Must use DECR since src and dest may overlap & dest>=src*/ MPN_COPY_DECR(ap+len, ap, k); } MPN_ZERO(ap, len); /* Zeroing the last limbs */ bx -= cnt + len*GMP_NUMB_BITS; /* Update Expo */ /* Last limb should be ok */ MPFR_ASSERTD(!(ap[len]&MPFR_LIMB_MASK((unsigned int) (-p) % GMP_NUMB_BITS))); } /* Check expo underflow */ if (MPFR_UNLIKELY(bx < __gmpfr_emin)) { MPFR_TMP_FREE(marker); /* inexact=0 */ DEBUG( printf("(D==0 Underflow)\n") ); if (rnd_mode == MPFR_RNDN && (bx < __gmpfr_emin - 1 || (/*inexact >= 0 &&*/ mpfr_powerof2_raw (a)))) rnd_mode = MPFR_RNDZ; return mpfr_underflow (a, rnd_mode, MPFR_SIGN(a)); } MPFR_SET_EXP (a, bx); /* No rounding is necessary since the result is exact */ MPFR_ASSERTD(ap[n-1] > ~ap[n-1]); MPFR_TMP_FREE(marker); return 0; } else /* if (d == 1) */ { /* | <-- b --> | <-- c --> */ mp_limb_t c0, mask; mp_size_t k; MPFR_UNSIGNED_MINUS_MODULO(sh, p); /* If we lose at least one bit, compute 2*b-c (Exact) * else compute b-c/2 */ bp = MPFR_MANT(b); cp = MPFR_MANT(c); k = n-1; limb = bp[k] - cp[k]/2; if (limb > MPFR_LIMB_HIGHBIT) { /* We can't lose precision: compute b-c/2 */ /* Shift c in the allocated temporary block */ SubD1NoLose: c0 = cp[0] & (MPFR_LIMB_ONE<<sh); cp = MPFR_TMP_LIMBS_ALLOC (n); mpn_rshift(cp, MPFR_MANT(c), n, 1); if (MPFR_LIKELY(c0 == 0)) { /* Result is exact: no need of rounding! */ ap = MPFR_MANT(a); mpn_sub_n (ap, bp, cp, n); MPFR_SET_EXP(a, bx); /* No expo overflow! */ /* No truncate or normalize is needed */ MPFR_ASSERTD(ap[n-1] > ~ap[n-1]); /* No rounding is necessary since the result is exact */ MPFR_TMP_FREE(marker); return 0; } ap = MPFR_MANT(a); mask = ~MPFR_LIMB_MASK(sh); cp[0] &= mask; /* Delete last bit of c */ mpn_sub_n (ap, bp, cp, n); MPFR_SET_EXP(a, bx); /* No expo overflow! */ MPFR_ASSERTD( !(ap[0] & ~mask) ); /* Check last bits */ /* No normalize is needed */ MPFR_ASSERTD(ap[n-1] > ~ap[n-1]); /* Rounding is necessary since c0 = 1*/ /* Cp =-1 and C'p+1=0 */ bcp = 1; bcp1 = 0; if (MPFR_LIKELY(rnd_mode == MPFR_RNDN)) { /* Even Rule apply: Check Ap-1 */ if (MPFR_LIKELY( (ap[0] & (MPFR_LIMB_ONE<<sh)) == 0) ) goto truncate; else goto sub_one_ulp; } MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(a)); if (rnd_mode == MPFR_RNDZ) goto sub_one_ulp; else goto truncate; } else if (MPFR_LIKELY(limb < MPFR_LIMB_HIGHBIT)) { /* We lose at least one bit of prec */ /* Calcul of 2*b-c (Exact) */ /* Shift b in the allocated temporary block */ SubD1Lose: bp = MPFR_TMP_LIMBS_ALLOC (n); mpn_lshift (bp, MPFR_MANT(b), n, 1); ap = MPFR_MANT(a); mpn_sub_n (ap, bp, cp, n); bx--; goto ExactNormalize; } else { /* Case: limb = 100000000000 */ /* Check while b[k] == c'[k] (C' is C shifted by 1) */ /* If b[k]<c'[k] => We lose at least one bit*/ /* If b[k]>c'[k] => We don't lose any bit */ /* If k==-1 => We don't lose any bit AND the result is 100000000000 0000000000 00000000000 */ mp_limb_t carry; do { carry = cp[k]&MPFR_LIMB_ONE; k--; } while (k>=0 && bp[k]==(carry=cp[k]/2+(carry<<(GMP_NUMB_BITS-1)))); if (MPFR_UNLIKELY(k<0)) { /*If carry then (sh==0 and Virtual c'[-1] > Virtual b[-1]) */ if (MPFR_UNLIKELY(carry)) /* carry = cp[0]&MPFR_LIMB_ONE */ { /* FIXME: Can be faster? */ MPFR_ASSERTD(sh == 0); goto SubD1Lose; } /* Result is a power of 2 */ ap = MPFR_MANT (a); MPN_ZERO (ap, n); ap[n-1] = MPFR_LIMB_HIGHBIT; MPFR_SET_EXP (a, bx); /* No expo overflow! */ /* No Normalize is needed*/ /* No Rounding is needed */ MPFR_TMP_FREE (marker); return 0; } /* carry = cp[k]/2+(cp[k-1]&1)<<(GMP_NUMB_BITS-1) = c'[k]*/ else if (bp[k] > carry) goto SubD1NoLose; else { MPFR_ASSERTD(bp[k]<carry); goto SubD1Lose; } } } } else if (MPFR_UNLIKELY(d >= p)) { ap = MPFR_MANT(a); MPFR_UNSIGNED_MINUS_MODULO(sh, p); /* We can't set A before since we use cp for rounding... */ /* Perform rounding: check if a=b or a=b-ulp(b) */ if (MPFR_UNLIKELY(d == p)) { /* cp == -1 and c'p+1 = ? */ bcp = 1; /* We need Cp+1 later for a very improbable case. */ bbcp = (MPFR_MANT(c)[n-1] & (MPFR_LIMB_ONE<<(GMP_NUMB_BITS-2))); /* We need also C'p+1 for an even more unprobable case... */ if (MPFR_LIKELY( bbcp )) bcp1 = 1; else { cp = MPFR_MANT(c); if (MPFR_UNLIKELY(cp[n-1] == MPFR_LIMB_HIGHBIT)) { mp_size_t k = n-1; do { k--; } while (k>=0 && cp[k]==0); bcp1 = (k>=0); } else bcp1 = 1; } DEBUG( printf("(D=P) Cp=-1 Cp+1=%d C'p+1=%d \n", bbcp!=0, bcp1!=0) ); bp = MPFR_MANT (b); /* Even if src and dest overlap, it is ok using MPN_COPY */ if (MPFR_LIKELY(rnd_mode == MPFR_RNDN)) { if (MPFR_UNLIKELY( bcp && bcp1==0 )) /* Cp=-1 and C'p+1=0: Even rule Apply! */ /* Check Ap-1 = Bp-1 */ if ((bp[0] & (MPFR_LIMB_ONE<<sh)) == 0) { MPN_COPY(ap, bp, n); goto truncate; } MPN_COPY(ap, bp, n); goto sub_one_ulp; } MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(a)); if (rnd_mode == MPFR_RNDZ) { MPN_COPY(ap, bp, n); goto sub_one_ulp; } else { MPN_COPY(ap, bp, n); goto truncate; } } else { /* Cp=0, Cp+1=-1 if d==p+1, C'p+1=-1 */ bcp = 0; bbcp = (d==p+1); bcp1 = 1; DEBUG( printf("(D>P) Cp=%d Cp+1=%d C'p+1=%d\n", bcp!=0,bbcp!=0,bcp1!=0) ); /* Need to compute C'p+2 if d==p+1 and if rnd_mode=NEAREST (Because of a very improbable case) */ if (MPFR_UNLIKELY(d==p+1 && rnd_mode==MPFR_RNDN)) { cp = MPFR_MANT(c); if (MPFR_UNLIKELY(cp[n-1] == MPFR_LIMB_HIGHBIT)) { mp_size_t k = n-1; do { k--; } while (k>=0 && cp[k]==0); bbcp1 = (k>=0); } else bbcp1 = 1; DEBUG( printf("(D>P) C'p+2=%d\n", bbcp1!=0) ); } /* Copy mantissa B in A */ MPN_COPY(ap, MPFR_MANT(b), n); /* Round */ if (MPFR_LIKELY(rnd_mode == MPFR_RNDN)) goto truncate; MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(a)); if (rnd_mode == MPFR_RNDZ) goto sub_one_ulp; else /* rnd_mode = AWAY */ goto truncate; } } else { mpfr_uexp_t dm; mp_size_t m; mp_limb_t mask; /* General case: 2 <= d < p */ MPFR_UNSIGNED_MINUS_MODULO(sh, p); cp = MPFR_TMP_LIMBS_ALLOC (n); /* Shift c in temporary allocated place */ dm = d % GMP_NUMB_BITS; m = d / GMP_NUMB_BITS; if (MPFR_UNLIKELY(dm == 0)) { /* dm = 0 and m > 0: Just copy */ MPFR_ASSERTD(m!=0); MPN_COPY(cp, MPFR_MANT(c)+m, n-m); MPN_ZERO(cp+n-m, m); } else if (MPFR_LIKELY(m == 0)) { /* dm >=2 and m == 0: just shift */ MPFR_ASSERTD(dm >= 2); mpn_rshift(cp, MPFR_MANT(c), n, dm); } else { /* dm > 0 and m > 0: shift and zero */ mpn_rshift(cp, MPFR_MANT(c)+m, n-m, dm); MPN_ZERO(cp+n-m, m); } DEBUG( mpfr_print_mant_binary("Before", MPFR_MANT(c), p) ); DEBUG( mpfr_print_mant_binary("B= ", MPFR_MANT(b), p) ); DEBUG( mpfr_print_mant_binary("After ", cp, p) ); /* Compute bcp=Cp and bcp1=C'p+1 */ if (MPFR_LIKELY(sh)) { /* Try to compute them from C' rather than C (FIXME: Faster?) */ bcp = (cp[0] & (MPFR_LIMB_ONE<<(sh-1))) ; if (MPFR_LIKELY( cp[0] & MPFR_LIMB_MASK(sh-1) )) bcp1 = 1; else { /* We can't compute C'p+1 from C'. Compute it from C */ /* Start from bit x=p-d+sh in mantissa C (+sh since we have already looked sh bits in C'!) */ mpfr_prec_t x = p-d+sh-1; if (MPFR_LIKELY(x>p)) /* We are already looked at all the bits of c, so C'p+1 = 0*/ bcp1 = 0; else { mp_limb_t *tp = MPFR_MANT(c); mp_size_t kx = n-1 - (x / GMP_NUMB_BITS); mpfr_prec_t sx = GMP_NUMB_BITS-1-(x%GMP_NUMB_BITS); DEBUG (printf ("(First) x=%lu Kx=%ld Sx=%lu\n", (unsigned long) x, (long) kx, (unsigned long) sx)); /* Looks at the last bits of limb kx (if sx=0 does nothing)*/ if (tp[kx] & MPFR_LIMB_MASK(sx)) bcp1 = 1; else { /*kx += (sx==0);*/ /*If sx==0, tp[kx] hasn't been checked*/ do { kx--; } while (kx>=0 && tp[kx]==0); bcp1 = (kx >= 0); } } } } else { /* Compute Cp and C'p+1 from C with sh=0 */ mp_limb_t *tp = MPFR_MANT(c); /* Start from bit x=p-d in mantissa C */ mpfr_prec_t x = p-d; mp_size_t kx = n-1 - (x / GMP_NUMB_BITS); mpfr_prec_t sx = GMP_NUMB_BITS-1-(x%GMP_NUMB_BITS); MPFR_ASSERTD(p >= d); bcp = (tp[kx] & (MPFR_LIMB_ONE<<sx)); /* Looks at the last bits of limb kx (If sx=0, does nothing)*/ if (tp[kx] & MPFR_LIMB_MASK(sx)) bcp1 = 1; else { /*kx += (sx==0);*/ /*If sx==0, tp[kx] hasn't been checked*/ do { kx--; } while (kx>=0 && tp[kx]==0); bcp1 = (kx>=0); } } DEBUG( printf("sh=%lu Cp=%d C'p+1=%d\n", sh, bcp!=0, bcp1!=0) ); /* Check if we can lose a bit, and if so compute Cp+1 and C'p+2 */ bp = MPFR_MANT(b); if (MPFR_UNLIKELY((bp[n-1]-cp[n-1]) <= MPFR_LIMB_HIGHBIT)) { /* We can lose a bit so we precompute Cp+1 and C'p+2 */ /* Test for trivial case: since C'p+1=0, Cp+1=0 and C'p+2 =0 */ if (MPFR_LIKELY(bcp1 == 0)) { bbcp = 0; bbcp1 = 0; } else /* bcp1 != 0 */ { /* We can lose a bit: compute Cp+1 and C'p+2 from mantissa C */ mp_limb_t *tp = MPFR_MANT(c); /* Start from bit x=(p+1)-d in mantissa C */ mpfr_prec_t x = p+1-d; mp_size_t kx = n-1 - (x/GMP_NUMB_BITS); mpfr_prec_t sx = GMP_NUMB_BITS-1-(x%GMP_NUMB_BITS); MPFR_ASSERTD(p > d); DEBUG (printf ("(pre) x=%lu Kx=%ld Sx=%lu\n", (unsigned long) x, (long) kx, (unsigned long) sx)); bbcp = (tp[kx] & (MPFR_LIMB_ONE<<sx)) ; /* Looks at the last bits of limb kx (If sx=0, does nothing)*/ /* If Cp+1=0, since C'p+1!=0, C'p+2=1 ! */ if (MPFR_LIKELY(bbcp==0 || (tp[kx]&MPFR_LIMB_MASK(sx)))) bbcp1 = 1; else { /*kx += (sx==0);*/ /*If sx==0, tp[kx] hasn't been checked*/ do { kx--; } while (kx>=0 && tp[kx]==0); bbcp1 = (kx>=0); DEBUG (printf ("(Pre) Scan done for %ld\n", (long) kx)); } } /*End of Bcp1 != 0*/ DEBUG( printf("(Pre) Cp+1=%d C'p+2=%d\n", bbcp!=0, bbcp1!=0) ); } /* End of "can lose a bit" */ /* Clean shifted C' */ mask = ~MPFR_LIMB_MASK (sh); cp[0] &= mask; /* Subtract the mantissa c from b in a */ ap = MPFR_MANT(a); mpn_sub_n (ap, bp, cp, n); DEBUG( mpfr_print_mant_binary("Sub= ", ap, p) ); /* Normalize: we lose at max one bit*/ if (MPFR_UNLIKELY(MPFR_LIMB_MSB(ap[n-1]) == 0)) { /* High bit is not set and we have to fix it! */ /* Ap >= 010000xxx001 */ mpn_lshift(ap, ap, n, 1); /* Ap >= 100000xxx010 */ if (MPFR_UNLIKELY(bcp!=0)) /* Check if Cp = -1 */ /* Since Cp == -1, we have to substract one more */ { mpn_sub_1(ap, ap, n, MPFR_LIMB_ONE<<sh); MPFR_ASSERTD(MPFR_LIMB_MSB(ap[n-1]) != 0); } /* Ap >= 10000xxx001 */ /* Final exponent -1 since we have shifted the mantissa */ bx--; /* Update bcp and bcp1 */ MPFR_ASSERTN(bbcp != (mp_limb_t) -1); MPFR_ASSERTN(bbcp1 != (mp_limb_t) -1); bcp = bbcp; bcp1 = bbcp1; /* We dont't have anymore a valid Cp+1! But since Ap >= 100000xxx001, the final sub can't unnormalize!*/ } MPFR_ASSERTD( !(ap[0] & ~mask) ); /* Rounding */ if (MPFR_LIKELY(rnd_mode == MPFR_RNDN)) { if (MPFR_LIKELY(bcp==0)) goto truncate; else if ((bcp1) || ((ap[0] & (MPFR_LIMB_ONE<<sh)) != 0)) goto sub_one_ulp; else goto truncate; } /* Update rounding mode */ MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(a)); if (rnd_mode == MPFR_RNDZ && (MPFR_LIKELY(bcp || bcp1))) goto sub_one_ulp; goto truncate; } MPFR_RET_NEVER_GO_HERE (); /* Sub one ulp to the result */ sub_one_ulp: mpn_sub_1 (ap, ap, n, MPFR_LIMB_ONE << sh); /* Result should be smaller than exact value: inexact=-1 */ inexact = -1; /* Check normalisation */ if (MPFR_UNLIKELY(MPFR_LIMB_MSB(ap[n-1]) == 0)) { /* ap was a power of 2, and we lose a bit */ /* Now it is 0111111111111111111[00000 */ mpn_lshift(ap, ap, n, 1); bx--; /* And the lost bit x depends on Cp+1, and Cp */ /* Compute Cp+1 if it isn't already compute (ie d==1) */ /* FIXME: Is this case possible? */ if (MPFR_UNLIKELY(d == 1)) bbcp = 0; DEBUG( printf("(SubOneUlp)Cp=%d, Cp+1=%d C'p+1=%d\n", bcp!=0,bbcp!=0,bcp1!=0)); /* Compute the last bit (Since we have shifted the mantissa) we need one more bit!*/ MPFR_ASSERTN(bbcp != (mp_limb_t) -1); if ( (rnd_mode == MPFR_RNDZ && bcp==0) || (rnd_mode==MPFR_RNDN && bbcp==0) || (bcp && bcp1==0) ) /*Exact result*/ { ap[0] |= MPFR_LIMB_ONE<<sh; if (rnd_mode == MPFR_RNDN) inexact = 1; DEBUG( printf("(SubOneUlp) Last bit set\n") ); } /* Result could be exact if C'p+1 = 0 and rnd == Zero since we have had one more bit to the result */ /* Fixme: rnd_mode == MPFR_RNDZ needed ? */ if (bcp1==0 && rnd_mode==MPFR_RNDZ) { DEBUG( printf("(SubOneUlp) Exact result\n") ); inexact = 0; } } goto end_of_sub; truncate: /* Check if the result is an exact power of 2: 100000000000 in which cases, we could have to do sub_one_ulp due to some nasty reasons: If Result is a Power of 2: + If rnd = AWAY, | If Cp=-1 and C'p+1 = 0, SubOneUlp and the result is EXACT. If Cp=-1 and C'p+1 =-1, SubOneUlp and the result is above. Otherwise truncate + If rnd = NEAREST, If Cp= 0 and Cp+1 =-1 and C'p+2=-1, SubOneUlp and the result is above If cp=-1 and C'p+1 = 0, SubOneUlp and the result is exact. Otherwise truncate. X bit should always be set if SubOneUlp*/ if (MPFR_UNLIKELY(ap[n-1] == MPFR_LIMB_HIGHBIT)) { mp_size_t k = n-1; do { k--; } while (k>=0 && ap[k]==0); if (MPFR_UNLIKELY(k<0)) { /* It is a power of 2! */ /* Compute Cp+1 if it isn't already compute (ie d==1) */ /* FIXME: Is this case possible? */ if (d == 1) bbcp=0; DEBUG( printf("(Truncate) Cp=%d, Cp+1=%d C'p+1=%d C'p+2=%d\n", \ bcp!=0, bbcp!=0, bcp1!=0, bbcp1!=0) ); MPFR_ASSERTN(bbcp != (mp_limb_t) -1); MPFR_ASSERTN((rnd_mode != MPFR_RNDN) || (bcp != 0) || (bbcp == 0) || (bbcp1 != (mp_limb_t) -1)); if (((rnd_mode != MPFR_RNDZ) && bcp) || ((rnd_mode == MPFR_RNDN) && (bcp == 0) && (bbcp) && (bbcp1))) { DEBUG( printf("(Truncate) Do sub\n") ); mpn_sub_1 (ap, ap, n, MPFR_LIMB_ONE << sh); mpn_lshift(ap, ap, n, 1); ap[0] |= MPFR_LIMB_ONE<<sh; bx--; /* FIXME: Explain why it works (or why not)... */ inexact = (bcp1 == 0) ? 0 : (rnd_mode==MPFR_RNDN) ? -1 : 1; goto end_of_sub; } } } /* Calcul of Inexact flag.*/ inexact = MPFR_LIKELY(bcp || bcp1) ? 1 : 0; end_of_sub: /* Update Expo */ /* FIXME: Is this test really useful? If d==0 : Exact case. This is never called. if 1 < d < p : bx=MPFR_EXP(b) or MPFR_EXP(b)-1 > MPFR_EXP(c) > emin if d == 1 : bx=MPFR_EXP(b). If we could lose any bits, the exact normalisation is called. if d >= p : bx=MPFR_EXP(b) >= MPFR_EXP(c) + p > emin After SubOneUlp, we could have one bit less. if 1 < d < p : bx >= MPFR_EXP(b)-2 >= MPFR_EXP(c) > emin if d == 1 : bx >= MPFR_EXP(b)-1 = MPFR_EXP(c) > emin. if d >= p : bx >= MPFR_EXP(b)-1 > emin since p>=2. */ MPFR_ASSERTD( bx >= __gmpfr_emin); /* if (MPFR_UNLIKELY(bx < __gmpfr_emin)) { DEBUG( printf("(Final Underflow)\n") ); if (rnd_mode == MPFR_RNDN && (bx < __gmpfr_emin - 1 || (inexact >= 0 && mpfr_powerof2_raw (a)))) rnd_mode = MPFR_RNDZ; MPFR_TMP_FREE(marker); return mpfr_underflow (a, rnd_mode, MPFR_SIGN(a)); } */ MPFR_SET_EXP (a, bx); MPFR_TMP_FREE(marker); MPFR_RET (inexact * MPFR_INT_SIGN (a)); }
/* Exact product. The number a is assumed to have enough allocated memory, where the trailing bits are regarded as being part of the input numbers (no reallocation is attempted and no check is performed as MPFR_TMP_INIT could have been used). The arguments b and c may actually be UBF numbers (mpfr_srcptr can be seen a bit like void *, but is stronger). This function does not change the flags, except in case of NaN. */ void mpfr_ubf_mul_exact (mpfr_ubf_ptr a, mpfr_srcptr b, mpfr_srcptr c) { MPFR_LOG_FUNC (("b[%Pu]=%.*Rg c[%Pu]=%.*Rg", mpfr_get_prec (b), mpfr_log_prec, b, mpfr_get_prec (c), mpfr_log_prec, c), ("a[%Pu]=%.*Rg", mpfr_get_prec (a), mpfr_log_prec, a)); MPFR_ASSERTD ((mpfr_ptr) a != b); MPFR_ASSERTD ((mpfr_ptr) a != c); MPFR_SIGN (a) = MPFR_MULT_SIGN (MPFR_SIGN (b), MPFR_SIGN (c)); if (MPFR_ARE_SINGULAR (b, c)) { if (MPFR_IS_NAN (b) || MPFR_IS_NAN (c)) MPFR_SET_NAN (a); else if (MPFR_IS_INF (b)) { if (MPFR_NOTZERO (c)) MPFR_SET_INF (a); else MPFR_SET_NAN (a); } else if (MPFR_IS_INF (c)) { if (!MPFR_IS_ZERO (b)) MPFR_SET_INF (a); else MPFR_SET_NAN (a); } else { MPFR_ASSERTD (MPFR_IS_ZERO(b) || MPFR_IS_ZERO(c)); MPFR_SET_ZERO (a); } } else { mpfr_exp_t e; mp_size_t bn, cn; mpfr_limb_ptr ap; mp_limb_t u, v; int m; /* Note about the code below: For the choice of the precision of * the result a, one could choose PREC(b) + PREC(c), instead of * taking whole limbs into account, but in most cases where one * would gain one limb, one would need to copy the significand * instead of a no-op (see the mul.c code). * But in the case MPFR_LIMB_MSB (u) == 0, if the result fits in * an-1 limbs, one could actually do * mpn_rshift (ap, ap, k, GMP_NUMB_BITS - 1) * instead of * mpn_lshift (ap, ap, k, 1) * to gain one limb (and reduce the precision), replacing a shift * by another one. Would this be interesting? */ bn = MPFR_LIMB_SIZE (b); cn = MPFR_LIMB_SIZE (c); ap = MPFR_MANT (a); u = (bn >= cn) ? mpn_mul (ap, MPFR_MANT (b), bn, MPFR_MANT (c), cn) : mpn_mul (ap, MPFR_MANT (c), cn, MPFR_MANT (b), bn); if (MPFR_UNLIKELY (MPFR_LIMB_MSB (u) == 0)) { m = 1; MPFR_DBGRES (v = mpn_lshift (ap, ap, bn + cn, 1)); MPFR_ASSERTD (v == 0); } else m = 0; if (! MPFR_IS_UBF (b) && ! MPFR_IS_UBF (c) && (e = MPFR_GET_EXP (b) + MPFR_GET_EXP (c) - m, MPFR_EXP_IN_RANGE (e))) { MPFR_SET_EXP (a, e); } else { mpz_t be, ce; mpz_init (MPFR_ZEXP (a)); /* This may involve copies of mpz_t, but exponents should not be very large integers anyway. */ mpfr_get_zexp (be, b); mpfr_get_zexp (ce, c); mpz_add (MPFR_ZEXP (a), be, ce); mpz_clear (be); mpz_clear (ce); mpz_sub_ui (MPFR_ZEXP (a), MPFR_ZEXP (a), m); MPFR_SET_UBF (a); } } }
int mpfr_mul_ui (mpfr_ptr y, mpfr_srcptr x, unsigned long int u, mpfr_rnd_t rnd_mode) { mp_limb_t *yp; mp_size_t xn; int cnt, inexact; MPFR_TMP_DECL (marker); if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x))) { if (MPFR_IS_NAN (x)) { MPFR_SET_NAN (y); MPFR_RET_NAN; } else if (MPFR_IS_INF (x)) { if (u != 0) { MPFR_SET_INF (y); MPFR_SET_SAME_SIGN (y, x); MPFR_RET (0); /* infinity is exact */ } else /* 0 * infinity */ { MPFR_SET_NAN (y); MPFR_RET_NAN; } } else /* x is zero */ { MPFR_ASSERTD (MPFR_IS_ZERO (x)); MPFR_SET_ZERO (y); MPFR_SET_SAME_SIGN (y, x); MPFR_RET (0); /* zero is exact */ } } else if (MPFR_UNLIKELY (u <= 1)) { if (u < 1) { MPFR_SET_ZERO (y); MPFR_SET_SAME_SIGN (y, x); MPFR_RET (0); /* zero is exact */ } else return mpfr_set (y, x, rnd_mode); } else if (MPFR_UNLIKELY (IS_POW2 (u))) return mpfr_mul_2si (y, x, MPFR_INT_CEIL_LOG2 (u), rnd_mode); yp = MPFR_MANT (y); xn = MPFR_LIMB_SIZE (x); MPFR_ASSERTD (xn < MP_SIZE_T_MAX); MPFR_TMP_MARK(marker); yp = MPFR_TMP_LIMBS_ALLOC (xn + 1); MPFR_ASSERTN (u == (mp_limb_t) u); yp[xn] = mpn_mul_1 (yp, MPFR_MANT (x), xn, u); /* x * u is stored in yp[xn], ..., yp[0] */ /* since the case u=1 was treated above, we have u >= 2, thus yp[xn] >= 1 since x was msb-normalized */ MPFR_ASSERTD (yp[xn] != 0); if (MPFR_LIKELY (MPFR_LIMB_MSB (yp[xn]) == 0)) { count_leading_zeros (cnt, yp[xn]); mpn_lshift (yp, yp, xn + 1, cnt); } else { cnt = 0; } /* now yp[xn], ..., yp[0] is msb-normalized too, and has at most PREC(x) + (GMP_NUMB_BITS - cnt) non-zero bits */ MPFR_RNDRAW (inexact, y, yp, (mpfr_prec_t) (xn + 1) * GMP_NUMB_BITS, rnd_mode, MPFR_SIGN (x), cnt -- ); MPFR_TMP_FREE (marker); cnt = GMP_NUMB_BITS - cnt; if (MPFR_UNLIKELY (__gmpfr_emax < MPFR_EMAX_MIN + cnt || MPFR_GET_EXP (x) > __gmpfr_emax - cnt)) return mpfr_overflow (y, rnd_mode, MPFR_SIGN(x)); MPFR_SET_EXP (y, MPFR_GET_EXP (x) + cnt); MPFR_SET_SAME_SIGN (y, x); return inexact; }
int mpfr_set_uj_2exp (mpfr_t x, uintmax_t j, intmax_t e, mp_rnd_t rnd) { unsigned int cnt, i; mp_size_t k, len; mp_limb_t limb; mp_limb_t yp[sizeof(uintmax_t) / sizeof(mp_limb_t)]; mpfr_t y; unsigned long uintmax_bit_size = sizeof(uintmax_t) * CHAR_BIT; unsigned long bpml = BITS_PER_MP_LIMB % uintmax_bit_size; /* Special case */ if (j == 0) { MPFR_SET_POS(x); MPFR_SET_ZERO(x); MPFR_RET(0); } MPFR_ASSERTN (sizeof(uintmax_t) % sizeof(mp_limb_t) == 0); /* Create an auxillary var */ MPFR_TMP_INIT1 (yp, y, uintmax_bit_size); k = numberof (yp); if (k == 1) limb = yp[0] = j; else { /* Note: either BITS_PER_MP_LIMB = uintmax_bit_size, then k = 1 the shift j >>= bpml is never done, or BITS_PER_MP_LIMB < uintmax_bit_size and bpml = BITS_PER_MP_LIMB. */ for (i = 0; i < k; i++, j >>= bpml) yp[i] = j; /* Only the low bits are copied */ /* Find the first limb not equal to zero. */ do { MPFR_ASSERTD (k > 0); limb = yp[--k]; } while (limb == 0); k++; } count_leading_zeros(cnt, limb); len = numberof (yp) - k; /* Normalize it: len = number of last 0 limb, k number of non-zero limbs */ if (MPFR_LIKELY(cnt)) mpn_lshift (yp+len, yp, k, cnt); /* Normalize the High Limb*/ else if (len != 0) MPN_COPY_DECR (yp+len, yp, k); /* Must use DECR */ if (len != 0) /* Note: when numberof(yp)==1, len is constant and null, so the compiler can optimize out this code. */ { if (len == 1) yp[0] = (mp_limb_t) 0; else MPN_ZERO (yp, len); /* Zeroing the last limbs */ } e += k * BITS_PER_MP_LIMB - cnt; /* Update Expo */ MPFR_ASSERTD (MPFR_LIMB_MSB(yp[numberof (yp) - 1]) != 0); /* Check expo underflow / overflow (can't use mpfr_check_range) */ if (MPFR_UNLIKELY(e < __gmpfr_emin)) { /* The following test is necessary because in the rounding to the * nearest mode, mpfr_underflow always rounds away from 0. In * this rounding mode, we need to round to 0 if: * _ |x| < 2^(emin-2), or * _ |x| = 2^(emin-2) and the absolute value of the exact * result is <= 2^(emin-2). */ if (rnd == GMP_RNDN && (e+1 < __gmpfr_emin || mpfr_powerof2_raw(y))) rnd = GMP_RNDZ; return mpfr_underflow (x, rnd, MPFR_SIGN_POS); } if (MPFR_UNLIKELY(e > __gmpfr_emax)) return mpfr_overflow (x, rnd, MPFR_SIGN_POS); MPFR_SET_EXP (y, e); /* Final: set x to y (rounding if necessary) */ return mpfr_set (x, y, rnd); }