/* * Assuming {bp, bn} is an approximation of a non-singular number * with error at most equal to 2^(EXP(b)-err0) (`err0' bits of b are known) * of direction unknown, check if we can round b toward zero with * precision prec. */ int mpfr_round_p (mp_limb_t *bp, mp_size_t bn, mpfr_exp_t err0, mpfr_prec_t prec) { mpfr_prec_t err; mp_size_t k, n; mp_limb_t tmp, mask; int s; err = (mpfr_prec_t) bn * GMP_NUMB_BITS; if (MPFR_UNLIKELY (err0 <= 0 || (mpfr_uexp_t) err0 <= prec || prec >= err)) return 0; /* can't round */ err = MIN (err, (mpfr_uexp_t) err0); k = prec / GMP_NUMB_BITS; s = GMP_NUMB_BITS - prec%GMP_NUMB_BITS; n = err / GMP_NUMB_BITS - k; MPFR_ASSERTD (n >= 0); MPFR_ASSERTD (bn > k); /* Check first limb */ bp += bn-1-k; tmp = *bp--; mask = s == GMP_NUMB_BITS ? MP_LIMB_T_MAX : MPFR_LIMB_MASK (s); tmp &= mask; if (MPFR_LIKELY (n == 0)) { /* prec and error are in the same limb */ s = GMP_NUMB_BITS - err % GMP_NUMB_BITS; MPFR_ASSERTD (s < GMP_NUMB_BITS); tmp >>= s; mask >>= s; return tmp != 0 && tmp != mask; }
/* * Check if x is a valid mpfr_t initializes by mpfr_init * Returns 0 if isn't valid */ int mpfr_check (mpfr_srcptr x) { mp_size_t s, i; mp_limb_t tmp; volatile mp_limb_t *xm; mpfr_prec_t prec; int rw; /* Check sign */ if (MPFR_SIGN(x) != MPFR_SIGN_POS && MPFR_SIGN(x) != MPFR_SIGN_NEG) return 0; /* Check precision */ prec = MPFR_PREC(x); if (prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX) return 0; /* Check mantissa */ xm = MPFR_MANT(x); if (xm == NULL) return 0; /* Check size of mantissa */ s = MPFR_GET_ALLOC_SIZE(x); if (s <= 0 || s > MP_SIZE_T_MAX || prec > (mpfr_prec_t) s * GMP_NUMB_BITS) return 0; /* Acces all the mp_limb of the mantissa: may do a seg fault */ for (i = 0 ; i < s ; i++) tmp = xm[i]; /* Check singular numbers (do not use MPFR_IS_PURE_FP() in order to avoid any assertion checking, as this function mpfr_check() does something similar by returning a Boolean instead of doing an abort if the format is incorrect). */ if (MPFR_IS_SINGULAR (x)) return MPFR_IS_ZERO(x) || MPFR_IS_NAN(x) || MPFR_IS_INF(x); /* Check the most significant limb (its MSB must be 1) */ if ((xm[MPFR_LAST_LIMB(x)] & MPFR_LIMB_HIGHBIT) == 0) return 0; /* Check the least significant limb (the trailing bits must be 0) */ rw = prec % GMP_NUMB_BITS; if (rw != 0) { tmp = MPFR_LIMB_MASK (GMP_NUMB_BITS - rw); if ((xm[0] & tmp) != 0) return 0; } /* Check exponent range */ if (MPFR_EXP (x) < __gmpfr_emin || MPFR_EXP (x) > __gmpfr_emax) return 0; return 1; }
exp -= sh; } else { /* this happens only if u == 1 and xp[xn-1] >= 1<<(BITS_PER_MP_LIMB-1). It might be better to handle the u == 1 case seperately ? */ 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 & MPFR_LIMB_MASK (sh); *yp ^= d; /* set to zero lowest sh bits */ MPFR_SET_EXP (y, exp); TMP_FREE(marker); if ((d == 0) && (inexact == 0)) return 0; /* result is exact */ switch (rnd_mode) { case GMP_RNDZ: MPFR_RET(-MPFR_INT_SIGN(x)); /* result is inexact */ case GMP_RNDU: if (MPFR_IS_POS(y))
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)); }
static void test_urandomb (long nbtests, mpfr_prec_t prec, int verbose) { mpfr_t x; int *tab, size_tab, k, sh, xn; double d, av = 0, var = 0, chi2 = 0, th; mpfr_exp_t emin; size_tab = (nbtests >= 1000 ? nbtests / 50 : 20); tab = (int *) calloc (size_tab, sizeof(int)); if (tab == NULL) { fprintf (stderr, "trandom: can't allocate memory in test_urandomb\n"); exit (1); } mpfr_init2 (x, prec); xn = 1 + (prec - 1) / mp_bits_per_limb; sh = xn * mp_bits_per_limb - prec; for (k = 0; k < nbtests; k++) { mpfr_urandomb (x, RANDS); /* check that lower bits are zero */ if (MPFR_MANT(x)[0] & MPFR_LIMB_MASK(sh)) { printf ("Error: mpfr_urandomb() returns invalid numbers:\n"); mpfr_print_binary (x); puts (""); exit (1); } d = mpfr_get_d1 (x); av += d; var += d*d; tab[(int)(size_tab * d)]++; } /* coverage test */ emin = mpfr_get_emin (); set_emin (1); /* the generated number in [0,1[ is not in the exponent range, except if it is zero */ k = mpfr_urandomb (x, RANDS); if (MPFR_IS_ZERO(x) == 0 && (k == 0 || mpfr_nan_p (x) == 0)) { printf ("Error in mpfr_urandomb, expected NaN, got "); mpfr_dump (x); exit (1); } set_emin (emin); mpfr_clear (x); if (!verbose) { free(tab); return; } av /= nbtests; var = (var / nbtests) - av * av; th = (double)nbtests / size_tab; printf("Average = %.5f\nVariance = %.5f\n", av, var); printf("Repartition for urandomb. Each integer should be close to %d.\n", (int)th); for (k = 0; k < size_tab; k++) { chi2 += (tab[k] - th) * (tab[k] - th) / th; printf("%d ", tab[k]); if (((k+1) & 7) == 0) printf("\n"); } printf("\nChi2 statistics value (with %d degrees of freedom) : %.5f\n\n", size_tab - 1, chi2); free(tab); return; }
int mpfr_sqrt (mpfr_ptr r, mpfr_srcptr u, mpfr_rnd_t rnd_mode) { mp_size_t rsize; /* number of limbs of r (plus 1 if exact limb multiple) */ mp_size_t rrsize; mp_size_t usize; /* number of limbs of u */ mp_size_t tsize; /* number of limbs of the sqrtrem remainder */ mp_size_t k; mp_size_t l; mpfr_limb_ptr rp, rp0; mpfr_limb_ptr up; mpfr_limb_ptr sp; mp_limb_t sticky0; /* truncated part of input */ mp_limb_t sticky1; /* truncated part of rp[0] */ mp_limb_t sticky; int odd_exp; int sh; /* number of extra bits in rp[0] */ int inexact; /* return ternary flag */ mpfr_exp_t expr; MPFR_TMP_DECL(marker); MPFR_LOG_FUNC (("x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (u), mpfr_log_prec, u, rnd_mode), ("y[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (r), mpfr_log_prec, r, inexact)); if (MPFR_UNLIKELY(MPFR_IS_SINGULAR(u))) { if (MPFR_IS_NAN(u)) { MPFR_SET_NAN(r); MPFR_RET_NAN; } else if (MPFR_IS_ZERO(u)) { /* 0+ or 0- */ MPFR_SET_SAME_SIGN(r, u); MPFR_SET_ZERO(r); MPFR_RET(0); /* zero is exact */ } else { MPFR_ASSERTD(MPFR_IS_INF(u)); /* sqrt(-Inf) = NAN */ if (MPFR_IS_NEG(u)) { MPFR_SET_NAN(r); MPFR_RET_NAN; } MPFR_SET_POS(r); MPFR_SET_INF(r); MPFR_RET(0); } } if (MPFR_UNLIKELY(MPFR_IS_NEG(u))) { MPFR_SET_NAN(r); MPFR_RET_NAN; } MPFR_SET_POS(r); MPFR_TMP_MARK (marker); MPFR_UNSIGNED_MINUS_MODULO(sh,MPFR_PREC(r)); if (sh == 0 && rnd_mode == MPFR_RNDN) sh = GMP_NUMB_BITS; /* ugly case */ rsize = MPFR_LIMB_SIZE(r) + (sh == GMP_NUMB_BITS); /* rsize is the number of limbs of r + 1 if exact limb multiple and rounding to nearest, this is the number of wanted limbs for the square root */ rrsize = rsize + rsize; usize = MPFR_LIMB_SIZE(u); /* number of limbs of u */ rp0 = MPFR_MANT(r); rp = (sh < GMP_NUMB_BITS) ? rp0 : MPFR_TMP_LIMBS_ALLOC (rsize); up = MPFR_MANT(u); sticky0 = MPFR_LIMB_ZERO; /* truncated part of input */ sticky1 = MPFR_LIMB_ZERO; /* truncated part of rp[0] */ odd_exp = (unsigned int) MPFR_GET_EXP (u) & 1; inexact = -1; /* return ternary flag */ sp = MPFR_TMP_LIMBS_ALLOC (rrsize); /* copy the most significant limbs of u to {sp, rrsize} */ if (MPFR_LIKELY(usize <= rrsize)) /* in case r and u have the same precision, we have indeed rrsize = 2 * usize */ { k = rrsize - usize; if (MPFR_LIKELY(k)) MPN_ZERO (sp, k); if (odd_exp) { if (MPFR_LIKELY(k)) sp[k - 1] = mpn_rshift (sp + k, up, usize, 1); else sticky0 = mpn_rshift (sp, up, usize, 1); } else MPN_COPY (sp + rrsize - usize, up, usize); } else /* usize > rrsize: truncate the input */ { k = usize - rrsize; if (odd_exp) sticky0 = mpn_rshift (sp, up + k, rrsize, 1); else MPN_COPY (sp, up + k, rrsize); l = k; while (sticky0 == MPFR_LIMB_ZERO && l != 0) sticky0 = up[--l]; } /* sticky0 is non-zero iff the truncated part of the input is non-zero */ /* mpn_rootrem with NULL 2nd argument is faster than mpn_sqrtrem, thus use it if available and if the user asked to use GMP internal functions */ #if defined(WANT_GMP_INTERNALS) && defined(HAVE___GMPN_ROOTREM) tsize = __gmpn_rootrem (rp, NULL, sp, rrsize, 2); #else tsize = mpn_sqrtrem (rp, NULL, sp, rrsize); #endif /* a return value of zero in mpn_sqrtrem indicates a perfect square */ sticky = sticky0 || tsize != 0; /* truncate low bits of rp[0] */ sticky1 = rp[0] & ((sh < GMP_NUMB_BITS) ? MPFR_LIMB_MASK(sh) : ~MPFR_LIMB_ZERO); rp[0] -= sticky1; sticky = sticky || sticky1; expr = (MPFR_GET_EXP(u) + odd_exp) / 2; /* exact */ if (rnd_mode == MPFR_RNDZ || rnd_mode == MPFR_RNDD || sticky == MPFR_LIMB_ZERO) { inexact = (sticky == MPFR_LIMB_ZERO) ? 0 : -1; goto truncate; } else if (rnd_mode == MPFR_RNDN) { /* if sh < GMP_NUMB_BITS, the round bit is bit (sh-1) of sticky1 and the sticky bit is formed by the low sh-1 bits from sticky1, together with the sqrtrem remainder and sticky0. */ if (sh < GMP_NUMB_BITS) { if (sticky1 & (MPFR_LIMB_ONE << (sh - 1))) { /* round bit is set */ if (sticky1 == (MPFR_LIMB_ONE << (sh - 1)) && tsize == 0 && sticky0 == 0) goto even_rule; else goto add_one_ulp; } else /* round bit is zero */ goto truncate; /* with the default inexact=-1 */ } else /* sh = GMP_NUMB_BITS: the round bit is the most significant bit of rp[0], and the remaining GMP_NUMB_BITS-1 bits contribute to the sticky bit */ { if (sticky1 & MPFR_LIMB_HIGHBIT) { /* round bit is set */ if (sticky1 == MPFR_LIMB_HIGHBIT && tsize == 0 && sticky0 == 0) goto even_rule; else goto add_one_ulp; } else /* round bit is zero */ goto truncate; /* with the default inexact=-1 */ } } else /* rnd_mode=GMP_RDNU, necessarily sticky <> 0, thus add 1 ulp */ goto add_one_ulp; even_rule: /* has to set inexact */ if (sh < GMP_NUMB_BITS) inexact = (rp[0] & (MPFR_LIMB_ONE << sh)) ? 1 : -1; else inexact = (rp[1] & MPFR_LIMB_ONE) ? 1 : -1; if (inexact == -1) goto truncate; /* else go through add_one_ulp */ add_one_ulp: inexact = 1; /* always here */ if (sh == GMP_NUMB_BITS) { rp ++; rsize --; sh = 0; } if (mpn_add_1 (rp0, rp, rsize, MPFR_LIMB_ONE << sh)) { expr ++; rp[rsize - 1] = MPFR_LIMB_HIGHBIT; } goto end; truncate: /* inexact = 0 or -1 */ if (sh == GMP_NUMB_BITS) MPN_COPY (rp0, rp + 1, rsize - 1); end: MPFR_ASSERTN (expr >= MPFR_EMIN_MIN && expr <= MPFR_EMAX_MAX); MPFR_EXP (r) = expr; MPFR_TMP_FREE(marker); return mpfr_check_range (r, inexact, rnd_mode); }
int mpfr_round_raw_generic( #if flag == 0 mp_limb_t *yp, #endif const mp_limb_t *xp, mpfr_prec_t xprec, int neg, mpfr_prec_t yprec, mpfr_rnd_t rnd_mode #if use_inexp != 0 , int *inexp #endif ) { mp_size_t xsize, nw; mp_limb_t himask, lomask, sb; int rw; #if flag == 0 int carry; #endif #if use_inexp == 0 int *inexp; #endif if (use_inexp) MPFR_ASSERTD(inexp != ((int*) 0)); MPFR_ASSERTD(neg == 0 || neg == 1); if (flag && !use_inexp && (xprec <= yprec || MPFR_IS_LIKE_RNDZ (rnd_mode, neg))) return 0; xsize = MPFR_PREC2LIMBS (xprec); nw = yprec / GMP_NUMB_BITS; rw = yprec & (GMP_NUMB_BITS - 1); if (MPFR_UNLIKELY(xprec <= yprec)) { /* No rounding is necessary. */ /* if yp=xp, maybe an overlap: MPN_COPY_DECR is OK when src <= dst */ if (MPFR_LIKELY(rw)) nw++; MPFR_ASSERTD(nw >= 1); MPFR_ASSERTD(nw >= xsize); if (use_inexp) *inexp = 0; #if flag == 0 MPN_COPY_DECR(yp + (nw - xsize), xp, xsize); MPN_ZERO(yp, nw - xsize); #endif return 0; } if (use_inexp || !MPFR_IS_LIKE_RNDZ(rnd_mode, neg)) { mp_size_t k = xsize - nw - 1; if (MPFR_LIKELY(rw)) { nw++; lomask = MPFR_LIMB_MASK (GMP_NUMB_BITS - rw); himask = ~lomask; } else { lomask = MPFR_LIMB_MAX; himask = MPFR_LIMB_MAX; } MPFR_ASSERTD(k >= 0); sb = xp[k] & lomask; /* First non-significant bits */ /* Rounding to nearest? */ if (MPFR_LIKELY (rnd_mode == MPFR_RNDN || rnd_mode == MPFR_RNDNA)) { /* Rounding to nearest */ mp_limb_t rbmask = MPFR_LIMB_ONE << (GMP_NUMB_BITS - 1 - rw); if ((sb & rbmask) == 0) /* rounding bit = 0 ? */ goto rnd_RNDZ; /* yes, behave like rounding toward zero */ /* Rounding to nearest with rounding bit = 1 */ if (MPFR_UNLIKELY (rnd_mode == MPFR_RNDNA)) /* FIXME: *inexp is not set. First, add a testcase that triggers the bug (at least with a sanitizer). */ goto rnd_RNDN_add_one_ulp; /* like rounding away from zero */ sb &= ~rbmask; /* first bits after the rounding bit */ while (MPFR_UNLIKELY(sb == 0) && k > 0) sb = xp[--k]; if (MPFR_UNLIKELY(sb == 0)) /* Even rounding. */ { /* sb == 0 && rnd_mode == MPFR_RNDN */ sb = xp[xsize - nw] & (himask ^ (himask << 1)); if (sb == 0) { if (use_inexp) *inexp = 2*MPFR_EVEN_INEX*neg-MPFR_EVEN_INEX; /* ((neg!=0)^(sb!=0)) ? MPFR_EVEN_INEX : -MPFR_EVEN_INEX */ /* since neg = 0 or 1 and sb = 0 */ #if flag == 0 MPN_COPY_INCR(yp, xp + xsize - nw, nw); yp[0] &= himask; #endif return 0; /* sb != 0 && rnd_mode != MPFR_RNDZ */ } else { /* sb != 0 && rnd_mode == MPFR_RNDN */ if (use_inexp) *inexp = MPFR_EVEN_INEX-2*MPFR_EVEN_INEX*neg; /* ((neg!=0)^(sb!=0)) ? MPFR_EVEN_INEX : -MPFR_EVEN_INEX */ /* since neg = 0 or 1 and sb != 0 */ goto rnd_RNDN_add_one_ulp; } } else /* sb != 0 && rnd_mode == MPFR_RNDN */ { if (use_inexp) *inexp = 1-2*neg; /* neg == 0 ? 1 : -1 */ rnd_RNDN_add_one_ulp: #if flag == 1 return 1; /* sb != 0 && rnd_mode != MPFR_RNDZ */ #else carry = mpn_add_1 (yp, xp + xsize - nw, nw, rw ? MPFR_LIMB_ONE << (GMP_NUMB_BITS - rw) : MPFR_LIMB_ONE); yp[0] &= himask; return carry; #endif } } /* Rounding toward zero? */ else if (MPFR_IS_LIKE_RNDZ(rnd_mode, neg)) { /* rnd_mode == MPFR_RNDZ */ rnd_RNDZ: while (MPFR_UNLIKELY(sb == 0) && k > 0) sb = xp[--k]; if (use_inexp) /* rnd_mode == MPFR_RNDZ and neg = 0 or 1 */ /* ((neg != 0) ^ (rnd_mode != MPFR_RNDZ)) ? 1 : -1 */ *inexp = MPFR_UNLIKELY(sb == 0) ? 0 : (2*neg-1); #if flag == 0 MPN_COPY_INCR(yp, xp + xsize - nw, nw); yp[0] &= himask; #endif return 0; /* sb != 0 && rnd_mode != MPFR_RNDZ */ } else { /* Rounding away from zero */ while (MPFR_UNLIKELY(sb == 0) && k > 0) sb = xp[--k]; if (MPFR_UNLIKELY(sb == 0)) { /* sb = 0 && rnd_mode != MPFR_RNDZ */ if (use_inexp) /* ((neg != 0) ^ (rnd_mode != MPFR_RNDZ)) ? 1 : -1 */ *inexp = 0; #if flag == 0 MPN_COPY_INCR(yp, xp + xsize - nw, nw); yp[0] &= himask; #endif return 0; } else { /* sb != 0 && rnd_mode != MPFR_RNDZ */ if (use_inexp) *inexp = 1-2*neg; /* neg == 0 ? 1 : -1 */ #if flag == 1 return 1; #else carry = mpn_add_1(yp, xp + xsize - nw, nw, rw ? MPFR_LIMB_ONE << (GMP_NUMB_BITS - rw) : 1); yp[0] &= himask; return carry; #endif } } } else { /* Rounding toward zero / no inexact flag */ #if flag == 0 if (MPFR_LIKELY(rw)) { nw++; himask = ~MPFR_LIMB_MASK (GMP_NUMB_BITS - rw); } else himask = MPFR_LIMB_MAX; MPN_COPY_INCR(yp, xp + xsize - nw, nw); yp[0] &= himask; #endif return 0; } }
/* compute sign(b) * (|b| + |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_add1sp (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode) { mpfr_uexp_t d; mpfr_prec_t p; unsigned int sh; mp_size_t n; mp_limb_t *ap, *cp; mpfr_exp_t bx; mp_limb_t limb; int inexact; 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)); MPFR_ASSERTD(MPFR_GET_EXP(b) >= MPFR_GET_EXP(c)); /* Read prec and num of limbs */ p = MPFR_PREC(b); n = MPFR_PREC2LIMBS (p); MPFR_UNSIGNED_MINUS_MODULO(sh, p); bx = MPFR_GET_EXP(b); d = (mpfr_uexp_t) (bx - MPFR_GET_EXP(c)); DEBUG (printf ("New add1sp with diff=%lu\n", (unsigned long) d)); if (MPFR_UNLIKELY(d == 0)) { /* d==0 */ DEBUG( mpfr_print_mant_binary("C= ", MPFR_MANT(c), p) ); DEBUG( mpfr_print_mant_binary("B= ", MPFR_MANT(b), p) ); bx++; /* exp + 1 */ ap = MPFR_MANT(a); limb = mpn_add_n(ap, MPFR_MANT(b), MPFR_MANT(c), n); DEBUG( mpfr_print_mant_binary("A= ", ap, p) ); MPFR_ASSERTD(limb != 0); /* There must be a carry */ limb = ap[0]; /* Get LSB (In fact, LSW) */ mpn_rshift(ap, ap, n, 1); /* Shift mantissa A */ ap[n-1] |= MPFR_LIMB_HIGHBIT; /* Set MSB */ ap[0] &= ~MPFR_LIMB_MASK(sh); /* Clear LSB bit */ if (MPFR_LIKELY((limb&(MPFR_LIMB_ONE<<sh)) == 0)) /* Check exact case */ { inexact = 0; goto set_exponent; } /* Zero: Truncate Nearest: Even Rule => truncate or add 1 Away: Add 1 */ if (MPFR_LIKELY(rnd_mode==MPFR_RNDN)) { if (MPFR_LIKELY((ap[0]&(MPFR_LIMB_ONE<<sh))==0)) { inexact = -1; goto set_exponent; } else goto add_one_ulp; } MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(b)); if (rnd_mode==MPFR_RNDZ) { inexact = -1; goto set_exponent; } else goto add_one_ulp; } else if (MPFR_UNLIKELY (d >= p)) { if (MPFR_LIKELY (d > p)) { /* d > p : Copy B in A */ /* Away: Add 1 Nearest: Trunc Zero: Trunc */ if (MPFR_LIKELY (rnd_mode==MPFR_RNDN || MPFR_IS_LIKE_RNDZ (rnd_mode, MPFR_IS_NEG (b)))) { copy_set_exponent: ap = MPFR_MANT (a); MPN_COPY (ap, MPFR_MANT(b), n); inexact = -1; goto set_exponent; } else { copy_add_one_ulp: ap = MPFR_MANT(a); MPN_COPY (ap, MPFR_MANT(b), n); goto add_one_ulp; } } else { /* d==p : Copy B in A */ /* Away: Add 1 Nearest: Even Rule if C is a power of 2, else Add 1 Zero: Trunc */ if (MPFR_LIKELY(rnd_mode==MPFR_RNDN)) { /* Check if C was a power of 2 */ 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); if (MPFR_UNLIKELY(k<0)) /* Power of 2: Even rule */ if ((MPFR_MANT (b)[0]&(MPFR_LIMB_ONE<<sh))==0) goto copy_set_exponent; } /* Not a Power of 2 */ goto copy_add_one_ulp; } else if (MPFR_IS_LIKE_RNDZ (rnd_mode, MPFR_IS_NEG (b))) goto copy_set_exponent; else goto copy_add_one_ulp; } } else { mp_limb_t mask; mp_limb_t bcp, bcp1; /* Cp and C'p+1 */ /* General case: 1 <= d < p */ cp = MPFR_TMP_LIMBS_ALLOC (n); /* Shift c in temporary allocated place */ { mpfr_uexp_t dm; mp_size_t m; 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 >=1 and m == 0: just shift */ MPFR_ASSERTD(dm >= 1); 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 > 0)) { /* Try to compute them from C' rather than C */ 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 /* sh == 0 */ { /* 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 { do { kx--; } while (kx>=0 && tp[kx]==0); bcp1 = (kx>=0); } } DEBUG (printf("sh=%u Cp=%lu C'p+1=%lu\n", sh, (unsigned long) bcp, (unsigned long) bcp1)); /* Clean shifted C' */ mask = ~MPFR_LIMB_MASK(sh); cp[0] &= mask; /* Add the mantissa c from b in a */ ap = MPFR_MANT(a); limb = mpn_add_n (ap, MPFR_MANT(b), cp, n); DEBUG( mpfr_print_mant_binary("Add= ", ap, p) ); /* Check for overflow */ if (MPFR_UNLIKELY (limb)) { limb = ap[0] & (MPFR_LIMB_ONE<<sh); /* Get LSB */ mpn_rshift (ap, ap, n, 1); /* Shift mantissa*/ bx++; /* Fix exponent */ ap[n-1] |= MPFR_LIMB_HIGHBIT; /* Set MSB */ ap[0] &= mask; /* Clear LSB bit */ bcp1 |= bcp; /* Recompute C'p+1 */ bcp = limb; /* Recompute Cp */ DEBUG (printf ("(Overflow) Cp=%lu C'p+1=%lu\n", (unsigned long) bcp, (unsigned long) bcp1)); DEBUG (mpfr_print_mant_binary ("Add= ", ap, p)); } /* Round: Zero: Truncate but could be exact. Away: Add 1 if Cp or C'p+1 !=0 Nearest: Truncate but could be exact if Cp==0 Add 1 if C'p+1 !=0, Even rule else */ if (MPFR_LIKELY(rnd_mode == MPFR_RNDN)) { if (MPFR_LIKELY(bcp == 0)) { inexact = MPFR_LIKELY(bcp1) ? -1 : 0; goto set_exponent; } else if (MPFR_UNLIKELY(bcp1==0) && (ap[0]&(MPFR_LIMB_ONE<<sh))==0) { inexact = -1; goto set_exponent; } else goto add_one_ulp; } MPFR_UPDATE_RND_MODE(rnd_mode, MPFR_IS_NEG(b)); if (rnd_mode == MPFR_RNDZ) { inexact = MPFR_LIKELY(bcp || bcp1) ? -1 : 0; goto set_exponent; } else { if (MPFR_UNLIKELY(bcp==0 && bcp1==0)) { inexact = 0; goto set_exponent; } else goto add_one_ulp; } } MPFR_ASSERTN(0); add_one_ulp: /* add one unit in last place to a */ DEBUG( printf("AddOneUlp\n") ); if (MPFR_UNLIKELY( mpn_add_1(ap, ap, n, MPFR_LIMB_ONE<<sh) )) { /* Case 100000x0 = 0x1111x1 + 1*/ DEBUG( printf("Pow of 2\n") ); bx++; ap[n-1] = MPFR_LIMB_HIGHBIT; } inexact = 1; set_exponent: if (MPFR_UNLIKELY(bx > __gmpfr_emax)) /* Check for overflow */ { DEBUG( printf("Overflow\n") ); MPFR_TMP_FREE(marker); MPFR_SET_SAME_SIGN(a,b); return mpfr_overflow(a, rnd_mode, MPFR_SIGN(a)); } MPFR_SET_EXP (a, bx); MPFR_SET_SAME_SIGN(a,b); MPFR_TMP_FREE(marker); MPFR_RET (inexact * MPFR_INT_SIGN (a)); }
int main (void) { mpfr_t a; mp_limb_t *p, tmp; mp_size_t s; mpfr_prec_t pr; int max; tests_start_mpfr (); for(pr = MPFR_PREC_MIN ; pr < 500 ; pr++) { mpfr_init2 (a, pr); if (!mpfr_check(a)) ERROR("for init"); /* Check special cases */ MPFR_SET_NAN(a); if (!mpfr_check(a)) ERROR("for nan"); MPFR_SET_POS(a); MPFR_SET_INF(a); if (!mpfr_check(a)) ERROR("for inf"); MPFR_SET_ZERO(a); if (!mpfr_check(a)) ERROR("for zero"); MPFR_EXP (a) = MPFR_EXP_MIN; if (mpfr_check(a)) ERROR("for EXP = MPFR_EXP_MIN"); /* Check var */ mpfr_set_ui(a, 2, MPFR_RNDN); if (!mpfr_check(a)) ERROR("for set_ui"); mpfr_clear_overflow(); max = 1000; /* Allows max 2^1000 bits for the exponent */ while ((!mpfr_overflow_p()) && (max>0)) { mpfr_mul(a, a, a, MPFR_RNDN); if (!mpfr_check(a)) ERROR("for mul"); max--; } if (max==0) ERROR("can't reach overflow"); mpfr_set_ui(a, 2137, MPFR_RNDN); /* Corrupt a and check for it */ MPFR_SIGN(a) = 2; if (mpfr_check(a)) ERROR("sgn"); MPFR_SET_POS(a); /* Check prec */ MPFR_PREC(a) = MPFR_PREC_MIN - 1; if (mpfr_check(a)) ERROR("precmin"); #if MPFR_VERSION_MAJOR < 3 /* Disable the test with MPFR >= 3 since mpfr_prec_t is now signed. The "if" below is sufficient, but the MPFR_PREC_MAX+1 generates a warning with GCC 4.4.4 even though the test is always false. */ if ((mpfr_prec_t) 0 - 1 > 0) { MPFR_PREC(a) = MPFR_PREC_MAX+1; if (mpfr_check(a)) ERROR("precmax"); } #endif MPFR_PREC(a) = pr; if (!mpfr_check(a)) ERROR("prec"); /* Check exponent */ MPFR_EXP(a) = MPFR_EXP_INVALID; if (mpfr_check(a)) ERROR("exp invalid"); MPFR_EXP(a) = -MPFR_EXP_INVALID; if (mpfr_check(a)) ERROR("-exp invalid"); MPFR_EXP(a) = 0; if (!mpfr_check(a)) ERROR("exp 0"); /* Check Mantissa */ p = MPFR_MANT(a); MPFR_MANT(a) = NULL; if (mpfr_check(a)) ERROR("Mantissa Null Ptr"); MPFR_MANT(a) = p; /* Check size */ s = MPFR_GET_ALLOC_SIZE(a); MPFR_SET_ALLOC_SIZE(a, 0); if (mpfr_check(a)) ERROR("0 size"); MPFR_SET_ALLOC_SIZE(a, MP_SIZE_T_MIN); if (mpfr_check(a)) ERROR("min size"); MPFR_SET_ALLOC_SIZE(a, MPFR_LIMB_SIZE(a)-1 ); if (mpfr_check(a)) ERROR("size < prec"); MPFR_SET_ALLOC_SIZE(a, s); /* Check normal form */ tmp = MPFR_MANT(a)[0]; if ((pr % GMP_NUMB_BITS) != 0) { MPFR_MANT(a)[0] = MPFR_LIMB_MAX; if (mpfr_check(a)) ERROR("last bits non 0"); } MPFR_MANT(a)[0] = tmp; MPFR_MANT(a)[MPFR_LIMB_SIZE(a)-1] &= MPFR_LIMB_MASK (GMP_NUMB_BITS-1); if (mpfr_check(a)) ERROR("last bits non 0"); /* Final */ mpfr_set_ui(a, 2137, MPFR_RNDN); if (!mpfr_check(a)) ERROR("after last set"); mpfr_clear (a); if (mpfr_check(a)) ERROR("after clear"); } tests_end_mpfr (); return 0; }
static void test_urandom (long nbtests, mpfr_prec_t prec, mpfr_rnd_t rnd, long bit_index, int verbose) { mpfr_t x; int *tab, size_tab, k, sh, xn; double d, av = 0, var = 0, chi2 = 0, th; mpfr_exp_t emin; mp_size_t limb_index = 0; mp_limb_t limb_mask = 0; long count = 0; int i; int inex = 1; size_tab = (nbtests >= 1000 ? nbtests / 50 : 20); tab = (int *) calloc (size_tab, sizeof(int)); if (tab == NULL) { fprintf (stderr, "trandom: can't allocate memory in test_urandom\n"); exit (1); } mpfr_init2 (x, prec); xn = 1 + (prec - 1) / mp_bits_per_limb; sh = xn * mp_bits_per_limb - prec; if (bit_index >= 0 && bit_index < prec) { /* compute the limb index and limb mask to fetch the bit #bit_index */ limb_index = (prec - bit_index) / mp_bits_per_limb; i = 1 + bit_index - (bit_index / mp_bits_per_limb) * mp_bits_per_limb; limb_mask = MPFR_LIMB_ONE << (mp_bits_per_limb - i); } for (k = 0; k < nbtests; k++) { i = mpfr_urandom (x, RANDS, rnd); inex = (i != 0) && inex; /* check that lower bits are zero */ if (MPFR_MANT(x)[0] & MPFR_LIMB_MASK(sh) && !MPFR_IS_ZERO (x)) { printf ("Error: mpfr_urandom() returns invalid numbers:\n"); mpfr_print_binary (x); puts (""); exit (1); } /* check that the value is in [0,1] */ if (mpfr_cmp_ui (x, 0) < 0 || mpfr_cmp_ui (x, 1) > 0) { printf ("Error: mpfr_urandom() returns number outside [0, 1]:\n"); mpfr_print_binary (x); puts (""); exit (1); } d = mpfr_get_d1 (x); av += d; var += d*d; i = (int)(size_tab * d); if (d == 1.0) i --; tab[i]++; if (limb_mask && (MPFR_MANT (x)[limb_index] & limb_mask)) count ++; } if (inex == 0) { /* one call in the loop pretended to return an exact number! */ printf ("Error: mpfr_urandom() returns a zero ternary value.\n"); exit (1); } /* coverage test */ emin = mpfr_get_emin (); for (k = 0; k < 5; k++) { set_emin (k+1); inex = mpfr_urandom (x, RANDS, rnd); if (( (rnd == MPFR_RNDZ || rnd == MPFR_RNDD) && (!MPFR_IS_ZERO (x) || inex != -1)) || ((rnd == MPFR_RNDU || rnd == MPFR_RNDA) && (mpfr_cmp_ui (x, 1 << k) != 0 || inex != +1)) || (rnd == MPFR_RNDN && (k > 0 || mpfr_cmp_ui (x, 1 << k) != 0 || inex != +1) && (!MPFR_IS_ZERO (x) || inex != -1))) { printf ("Error: mpfr_urandom() do not handle correctly a restricted" " exponent range.\nrounding mode: %s\nternary value: %d\n" "random value: ", mpfr_print_rnd_mode (rnd), inex); mpfr_print_binary (x); puts (""); exit (1); } } set_emin (emin); mpfr_clear (x); if (!verbose) { free(tab); return; } av /= nbtests; var = (var / nbtests) - av * av; th = (double)nbtests / size_tab; printf ("Average = %.5f\nVariance = %.5f\n", av, var); printf ("Repartition for urandom with rounding mode %s. " "Each integer should be close to %d.\n", mpfr_print_rnd_mode (rnd), (int)th); for (k = 0; k < size_tab; k++) { chi2 += (tab[k] - th) * (tab[k] - th) / th; printf("%d ", tab[k]); if (((k+1) & 7) == 0) printf("\n"); } printf("\nChi2 statistics value (with %d degrees of freedom) : %.5f\n", size_tab - 1, chi2); if (limb_mask) printf ("Bit #%ld is set %ld/%ld = %.1f %% of time\n", bit_index, count, nbtests, count * 100.0 / nbtests); puts (""); free(tab); return; }
int mpfr_round_raw_generic( #if flag == 0 mp_limb_t *yp, #endif const mp_limb_t *xp, mpfr_prec_t xprec, int neg, mpfr_prec_t yprec, mpfr_rnd_t rnd_mode #if use_inexp != 0 , int *inexp #endif ) { mp_size_t xsize, nw; mp_limb_t himask, lomask, sb; int rw; #if flag == 0 int carry; #endif #if use_inexp == 0 int *inexp; #endif if (use_inexp) MPFR_ASSERTD(inexp != ((int*) 0)); MPFR_ASSERTD(neg == 0 || neg == 1); if (flag && !use_inexp && (xprec <= yprec || MPFR_IS_LIKE_RNDZ (rnd_mode, neg))) return 0; xsize = (xprec-1)/GMP_NUMB_BITS + 1; nw = yprec / GMP_NUMB_BITS; rw = yprec & (GMP_NUMB_BITS - 1); if (MPFR_UNLIKELY(xprec <= yprec)) { /* No rounding is necessary. */ /* if yp=xp, maybe an overlap: MPN_COPY_DECR is ok when src <= dst */ if (MPFR_LIKELY(rw)) nw++; MPFR_ASSERTD(nw >= 1); MPFR_ASSERTD(nw >= xsize); if (use_inexp) *inexp = 0; #if flag == 0 MPN_COPY_DECR(yp + (nw - xsize), xp, xsize); MPN_ZERO(yp, nw - xsize); #endif return 0; } if (use_inexp || !MPFR_IS_LIKE_RNDZ(rnd_mode, neg)) { mp_size_t k = xsize - nw - 1; if (MPFR_LIKELY(rw)) { nw++; lomask = MPFR_LIMB_MASK (GMP_NUMB_BITS - rw); himask = ~lomask; } else { lomask = ~(mp_limb_t) 0; himask = ~(mp_limb_t) 0; } MPFR_ASSERTD(k >= 0); sb = xp[k] & lomask; /* First non-significant bits */ /* Rounding to nearest ? */ if (MPFR_LIKELY( rnd_mode == MPFR_RNDN) ) { /* Rounding to nearest */ mp_limb_t rbmask = MPFR_LIMB_ONE << (GMP_NUMB_BITS - 1 - rw); if (sb & rbmask) /* rounding bit */ sb &= ~rbmask; /* it is 1, clear it */ else { /* Rounding bit is 0, behave like rounding to 0 */ goto rnd_RNDZ; } while (MPFR_UNLIKELY(sb == 0) && k > 0) sb = xp[--k]; /* rounding to nearest, with rounding bit = 1 */ if (MPFR_UNLIKELY(sb == 0)) /* Even rounding. */ { /* sb == 0 && rnd_mode == MPFR_RNDN */ sb = xp[xsize - nw] & (himask ^ (himask << 1)); if (sb == 0) { if (use_inexp) *inexp = 2*MPFR_EVEN_INEX*neg-MPFR_EVEN_INEX; /* ((neg!=0)^(sb!=0)) ? MPFR_EVEN_INEX : -MPFR_EVEN_INEX;*/ /* Since neg = 0 or 1 and sb=0*/ #if flag == 1 return 0 /*sb != 0 && rnd_mode != MPFR_RNDZ */; #else MPN_COPY_INCR(yp, xp + xsize - nw, nw); yp[0] &= himask; return 0; #endif } else { /* sb != 0 && rnd_mode == MPFR_RNDN */ if (use_inexp) *inexp = MPFR_EVEN_INEX-2*MPFR_EVEN_INEX*neg; /*((neg!=0)^(sb!=0))? MPFR_EVEN_INEX : -MPFR_EVEN_INEX; */ /*Since neg= 0 or 1 and sb != 0 */ goto rnd_RNDN_add_one_ulp; } } else /* sb != 0 && rnd_mode == MPFR_RNDN*/ { if (use_inexp) /* *inexp = (neg == 0) ? 1 : -1; but since neg = 0 or 1 */ *inexp = 1-2*neg; rnd_RNDN_add_one_ulp: #if flag == 1 return 1; /*sb != 0 && rnd_mode != MPFR_RNDZ;*/ #else carry = mpn_add_1 (yp, xp + xsize - nw, nw, rw ? MPFR_LIMB_ONE << (GMP_NUMB_BITS - rw) : MPFR_LIMB_ONE); yp[0] &= himask; return carry; #endif } } /* Rounding to Zero ? */ else if (MPFR_IS_LIKE_RNDZ(rnd_mode, neg)) { /* rnd_mode == MPFR_RNDZ */ rnd_RNDZ: while (MPFR_UNLIKELY(sb == 0) && k > 0) sb = xp[--k]; if (use_inexp) /* rnd_mode == MPFR_RNDZ and neg = 0 or 1 */ /* (neg != 0) ^ (rnd_mode != MPFR_RNDZ)) ? 1 : -1);*/ *inexp = MPFR_UNLIKELY(sb == 0) ? 0 : (2*neg-1); #if flag == 1 return 0; /*sb != 0 && rnd_mode != MPFR_RNDZ;*/ #else MPN_COPY_INCR(yp, xp + xsize - nw, nw); yp[0] &= himask; return 0; #endif } else { /* rnd_mode = Away */ while (MPFR_UNLIKELY(sb == 0) && k > 0) sb = xp[--k]; if (MPFR_UNLIKELY(sb == 0)) { /* sb = 0 && rnd_mode != MPFR_RNDZ */ if (use_inexp) /* (neg != 0) ^ (rnd_mode != MPFR_RNDZ)) ? 1 : -1);*/ *inexp = 0; #if flag == 1 return 0; #else MPN_COPY_INCR(yp, xp + xsize - nw, nw); yp[0] &= himask; return 0; #endif } else { /* sb != 0 && rnd_mode != MPFR_RNDZ */ if (use_inexp) /* (neg != 0) ^ (rnd_mode != MPFR_RNDZ)) ? 1 : -1);*/ *inexp = 1-2*neg; #if flag == 1 return 1; #else carry = mpn_add_1(yp, xp + xsize - nw, nw, rw ? MPFR_LIMB_ONE << (GMP_NUMB_BITS - rw) : 1); yp[0] &= himask; return carry; #endif } } } else { /* Roundind mode = Zero / No inexact flag */ #if flag == 1 return 0 /*sb != 0 && rnd_mode != MPFR_RNDZ*/; #else if (MPFR_LIKELY(rw)) { nw++; himask = ~MPFR_LIMB_MASK (GMP_NUMB_BITS - rw); } else himask = ~(mp_limb_t) 0; MPN_COPY_INCR(yp, xp + xsize - nw, nw); yp[0] &= himask; return 0; #endif } }
int main (void) { mpfr_t a; mp_limb_t *p, tmp; mp_size_t s; mpfr_prec_t pr; int max; tests_start_mpfr (); for(pr = MPFR_PREC_MIN ; pr < 500 ; pr++) { mpfr_init2 (a, pr); if (!mpfr_check(a)) ERROR("for init"); /* Check special cases */ MPFR_SET_NAN(a); if (!mpfr_check(a)) ERROR("for nan"); MPFR_SET_POS(a); MPFR_SET_INF(a); if (!mpfr_check(a)) ERROR("for inf"); MPFR_SET_ZERO(a); if (!mpfr_check(a)) ERROR("for zero"); /* Check var */ mpfr_set_ui(a, 2, GMP_RNDN); if (!mpfr_check(a)) ERROR("for set_ui"); mpfr_clear_overflow(); max = 1000; /* Allows max 2^1000 bits for the exponent */ while ((!mpfr_overflow_p()) && (max>0)) { mpfr_mul(a, a, a, GMP_RNDN); if (!mpfr_check(a)) ERROR("for mul"); max--; } if (max==0) ERROR("can't reach overflow"); mpfr_set_ui(a, 2137, GMP_RNDN); /* Corrupt a and check for it */ MPFR_SIGN(a) = 2; if (mpfr_check(a)) ERROR("sgn"); MPFR_SET_POS(a); /* Check prec */ MPFR_PREC(a) = 1; if (mpfr_check(a)) ERROR("precmin"); MPFR_PREC(a) = MPFR_PREC_MAX+1; if (mpfr_check(a)) ERROR("precmax"); MPFR_PREC(a) = pr; if (!mpfr_check(a)) ERROR("prec"); /* Check exponent */ MPFR_EXP(a) = MPFR_EXP_INVALID; if (mpfr_check(a)) ERROR("exp invalid"); MPFR_EXP(a) = -MPFR_EXP_INVALID; if (mpfr_check(a)) ERROR("-exp invalid"); MPFR_EXP(a) = 0; if (!mpfr_check(a)) ERROR("exp 0"); /* Check Mantissa */ p = MPFR_MANT(a); MPFR_MANT(a) = NULL; if (mpfr_check(a)) ERROR("Mantissa Null Ptr"); MPFR_MANT(a) = p; /* Check size */ s = MPFR_GET_ALLOC_SIZE(a); MPFR_SET_ALLOC_SIZE(a, 0); if (mpfr_check(a)) ERROR("0 size"); MPFR_SET_ALLOC_SIZE(a, MP_SIZE_T_MIN); if (mpfr_check(a)) ERROR("min size"); MPFR_SET_ALLOC_SIZE(a, MPFR_LIMB_SIZE(a)-1 ); if (mpfr_check(a)) ERROR("size < prec"); MPFR_SET_ALLOC_SIZE(a, s); /* Check normal form */ tmp = MPFR_MANT(a)[0]; if ((pr % BITS_PER_MP_LIMB) != 0) { MPFR_MANT(a)[0] = ~0; if (mpfr_check(a)) ERROR("last bits non 0"); } MPFR_MANT(a)[0] = tmp; MPFR_MANT(a)[MPFR_LIMB_SIZE(a)-1] &= MPFR_LIMB_MASK (BITS_PER_MP_LIMB-1); if (mpfr_check(a)) ERROR("last bits non 0"); /* Final */ mpfr_set_ui(a, 2137, GMP_RNDN); if (!mpfr_check(a)) ERROR("after last set"); mpfr_clear (a); if (mpfr_check(a)) ERROR("after clear"); } tests_end_mpfr (); return 0; }