REGPARM_ATTR (1) static void cfdiv_q_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt, int dir) { mp_size_t wsize, usize, abs_usize, limb_cnt, i; mp_srcptr up; mp_ptr wp; mp_limb_t round, rmask; usize = SIZ (u); abs_usize = ABS (usize); limb_cnt = cnt / GMP_NUMB_BITS; wsize = abs_usize - limb_cnt; if (wsize <= 0) { /* u < 2**cnt, so result 1, 0 or -1 according to rounding */ PTR(w)[0] = 1; SIZ(w) = (usize == 0 || (usize ^ dir) < 0 ? 0 : dir); return; } /* +1 limb to allow for mpn_add_1 below */ MPZ_REALLOC (w, wsize+1); /* Check for rounding if direction matches u sign. Set round if we're skipping non-zero limbs. */ up = PTR(u); round = 0; rmask = ((usize ^ dir) >= 0 ? MP_LIMB_T_MAX : 0); if (rmask != 0) for (i = 0; i < limb_cnt && round == 0; i++) round = up[i]; wp = PTR(w); cnt %= GMP_NUMB_BITS; if (cnt != 0) { round |= rmask & mpn_rshift (wp, up + limb_cnt, wsize, cnt); wsize -= (wp[wsize - 1] == 0); } else MPN_COPY_INCR (wp, up + limb_cnt, wsize); if (round != 0) { if (wsize != 0) { mp_limb_t cy; cy = mpn_add_1 (wp, wp, wsize, CNST_LIMB(1)); wp[wsize] = cy; wsize += cy; } else { /* We shifted something to zero. */ wp[0] = 1; wsize = 1; } } SIZ(w) = (usize >= 0 ? wsize : -wsize); }
void mpi_tdiv_q_2exp( MPI w, MPI u, unsigned count ) { mpi_size_t usize, wsize; mpi_size_t limb_cnt; usize = u->nlimbs; limb_cnt = count / BITS_PER_MPI_LIMB; wsize = usize - limb_cnt; if( limb_cnt >= usize ) w->nlimbs = 0; else { mpi_ptr_t wp; mpi_ptr_t up; RESIZE_IF_NEEDED( w, wsize ); wp = w->d; up = u->d; count %= BITS_PER_MPI_LIMB; if( count ) { mpihelp_rshift( wp, up + limb_cnt, wsize, count ); wsize -= !wp[wsize - 1]; } else { MPN_COPY_INCR( wp, up + limb_cnt, wsize); } w->nlimbs = wsize; } }
void mpf_set_prec (mpf_ptr x, mp_bitcnt_t new_prec_in_bits) { mp_size_t old_prec, new_prec, new_prec_plus1; mp_size_t size, sign; mp_ptr xp; new_prec = __GMPF_BITS_TO_PREC (new_prec_in_bits); old_prec = PREC(x); /* do nothing if already the right precision */ if (new_prec == old_prec) return; PREC(x) = new_prec; new_prec_plus1 = new_prec + 1; /* retain most significant limbs */ sign = SIZ(x); size = ABS (sign); xp = PTR(x); if (size > new_prec_plus1) { SIZ(x) = (sign >= 0 ? new_prec_plus1 : -new_prec_plus1); MPN_COPY_INCR (xp, xp + size - new_prec_plus1, new_prec_plus1); } PTR(x) = __GMP_REALLOCATE_FUNC_LIMBS (xp, old_prec+1, new_prec_plus1); }
static void mpz_to_mpn (mp_ptr ap, mp_size_t an, const mpz_t b) { mp_size_t bn = mpz_size (b); ASSERT_ALWAYS (bn <= an); MPN_COPY_INCR (ap, mpz_limbs_read (b), bn); MPN_ZERO (ap + bn, an - bn); }
void mpf_trunc (mpf_ptr r, mpf_srcptr u) { mp_ptr rp; mp_srcptr up; mp_size_t size, asize, prec; mp_exp_t exp; exp = EXP(u); size = SIZ(u); if (size == 0 || exp <= 0) { /* u is only a fraction */ SIZ(r) = 0; EXP(r) = 0; return; } up = PTR(u); EXP(r) = exp; asize = ABS (size); up += asize; /* skip fraction part of u */ asize = MIN (asize, exp); /* don't lose precision in the copy */ prec = PREC(r) + 1; /* skip excess over target precision */ asize = MIN (asize, prec); up -= asize; rp = PTR(r); SIZ(r) = (size >= 0 ? asize : -asize); if (rp != up) MPN_COPY_INCR (rp, up, asize); }
mp_limb_t mpn_dcpi1_divappr_q (mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn, gmp_pi1_t *dinv) { mp_size_t qn; mp_limb_t qh, cy, qsave; mp_ptr tp; TMP_DECL; TMP_MARK; ASSERT (dn >= 6); ASSERT (nn > dn); ASSERT (dp[dn-1] & GMP_NUMB_HIGHBIT); qn = nn - dn; qp += qn; np += nn; dp += dn; if (qn >= dn) { qn++; /* pretend we'll need an extra limb */ /* Reduce qn mod dn without division, optimizing small operations. */ do qn -= dn; while (qn > dn); qp -= qn; /* point at low limb of next quotient block */ np -= qn; /* point in the middle of partial remainder */ tp = TMP_SALLOC_LIMBS (dn); /* Perform the typically smaller block first. */ if (qn == 1) { mp_limb_t q, n2, n1, n0, d1, d0; /* Handle qh up front, for simplicity. */ qh = mpn_cmp (np - dn + 1, dp - dn, dn) >= 0; if (qh) ASSERT_NOCARRY (mpn_sub_n (np - dn + 1, np - dn + 1, dp - dn, dn)); /* A single iteration of schoolbook: One 3/2 division, followed by the bignum update and adjustment. */ n2 = np[0]; n1 = np[-1]; n0 = np[-2]; d1 = dp[-1]; d0 = dp[-2]; ASSERT (n2 < d1 || (n2 == d1 && n1 <= d0)); if (UNLIKELY (n2 == d1) && n1 == d0) { q = GMP_NUMB_MASK; cy = mpn_submul_1 (np - dn, dp - dn, dn, q); ASSERT (cy == n2); } else { udiv_qr_3by2 (q, n1, n0, n2, n1, n0, d1, d0, dinv->inv32); if (dn > 2) { mp_limb_t cy, cy1; cy = mpn_submul_1 (np - dn, dp - dn, dn - 2, q); cy1 = n0 < cy; n0 = (n0 - cy) & GMP_NUMB_MASK; cy = n1 < cy1; n1 = (n1 - cy1) & GMP_NUMB_MASK; np[-2] = n0; if (UNLIKELY (cy != 0)) { n1 += d1 + mpn_add_n (np - dn, np - dn, dp - dn, dn - 1); qh -= (q == 0); q = (q - 1) & GMP_NUMB_MASK; } } else np[-2] = n0; np[-1] = n1; } qp[0] = q; } else { if (qn == 2) qh = mpn_divrem_2 (qp, 0L, np - 2, 4, dp - 2); else if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD)) qh = mpn_sbpi1_div_qr (qp, np - qn, 2 * qn, dp - qn, qn, dinv->inv32); else qh = mpn_dcpi1_div_qr_n (qp, np - qn, dp - qn, qn, dinv, tp); if (qn != dn) { if (qn > dn - qn) mpn_mul (tp, qp, qn, dp - dn, dn - qn); else mpn_mul (tp, dp - dn, dn - qn, qp, qn); cy = mpn_sub_n (np - dn, np - dn, tp, dn); if (qh != 0) cy += mpn_sub_n (np - dn + qn, np - dn + qn, dp - dn, dn - qn); while (cy != 0) { qh -= mpn_sub_1 (qp, qp, qn, 1); cy -= mpn_add_n (np - dn, np - dn, dp - dn, dn); } } } qn = nn - dn - qn + 1; while (qn > dn) { qp -= dn; np -= dn; mpn_dcpi1_div_qr_n (qp, np - dn, dp - dn, dn, dinv, tp); qn -= dn; } /* Since we pretended we'd need an extra quotient limb before, we now have made sure the code above left just dn-1=qn quotient limbs to develop. Develop that plus a guard limb. */ qn--; qp -= qn; np -= dn; qsave = qp[qn]; mpn_dcpi1_divappr_q_n (qp, np - dn, dp - dn, dn, dinv, tp); MPN_COPY_INCR (qp, qp + 1, qn); qp[qn] = qsave; } else /* (qn < dn) */ { mp_ptr q2p; #if 0 /* not possible since we demand nn > dn */ if (qn == 0) { qh = mpn_cmp (np - dn, dp - dn, dn) >= 0; if (qh) mpn_sub_n (np - dn, np - dn, dp - dn, dn); TMP_FREE; return qh; } #endif qp -= qn; /* point at low limb of next quotient block */ np -= qn; /* point in the middle of partial remainder */ q2p = TMP_SALLOC_LIMBS (qn + 1); /* Should we at all check DC_DIVAPPR_Q_THRESHOLD here, or reply on callers not to be silly? */ if (BELOW_THRESHOLD (qn, DC_DIVAPPR_Q_THRESHOLD)) { qh = mpn_sbpi1_divappr_q (q2p, np - qn - 2, 2 * (qn + 1), dp - (qn + 1), qn + 1, dinv->inv32); } else { /* It is tempting to use qp for recursive scratch and put quotient in tp, but the recursive scratch needs one limb too many. */ tp = TMP_SALLOC_LIMBS (qn + 1); qh = mpn_dcpi1_divappr_q_n (q2p, np - qn - 2, dp - (qn + 1), qn + 1, dinv, tp); } MPN_COPY (qp, q2p + 1, qn); } TMP_FREE; return qh; }
static void mpf_ceil_or_floor (mpf_ptr r, mpf_srcptr u, int dir) { mp_ptr rp, up, p; mp_size_t size, asize, prec; mp_exp_t exp; size = SIZ(u); if (size == 0) { zero: SIZ(r) = 0; EXP(r) = 0; return; } rp = PTR(r); exp = EXP(u); if (exp <= 0) { /* u is only a fraction */ if ((size ^ dir) < 0) goto zero; rp[0] = 1; EXP(r) = 1; SIZ(r) = dir; return; } EXP(r) = exp; up = PTR(u); asize = ABS (size); up += asize; /* skip fraction part of u */ asize = MIN (asize, exp); /* don't lose precision in the copy */ prec = PREC (r) + 1; /* skip excess over target precision */ asize = MIN (asize, prec); up -= asize; if ((size ^ dir) >= 0) { /* rounding direction matches sign, must increment if ignored part is non-zero */ for (p = PTR(u); p != up; p++) { if (*p != 0) { if (mpn_add_1 (rp, up, asize, CNST_LIMB(1))) { /* was all 0xFF..FFs, which have become zeros, giving just a carry */ rp[0] = 1; asize = 1; EXP(r)++; } SIZ(r) = (size >= 0 ? asize : -asize); return; } } } SIZ(r) = (size >= 0 ? asize : -asize); if (rp != up) MPN_COPY_INCR (rp, up, asize); }
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; } }
void mpf_sub (mpf_ptr r, mpf_srcptr u, mpf_srcptr v) { mp_srcptr up, vp; mp_ptr rp, tp; mp_size_t usize, vsize, rsize; mp_size_t prec; mp_exp_t exp; mp_size_t ediff; int negate; TMP_DECL; usize = u->_mp_size; vsize = v->_mp_size; /* Handle special cases that don't work in generic code below. */ if (usize == 0) { mpf_neg (r, v); return; } if (vsize == 0) { if (r != u) mpf_set (r, u); return; } /* If signs of U and V are different, perform addition. */ if ((usize ^ vsize) < 0) { __mpf_struct v_negated; v_negated._mp_size = -vsize; v_negated._mp_exp = v->_mp_exp; v_negated._mp_d = v->_mp_d; mpf_add (r, u, &v_negated); return; } TMP_MARK; /* Signs are now known to be the same. */ negate = usize < 0; /* Make U be the operand with the largest exponent. */ if (u->_mp_exp < v->_mp_exp) { mpf_srcptr t; t = u; u = v; v = t; negate ^= 1; usize = u->_mp_size; vsize = v->_mp_size; } usize = ABS (usize); vsize = ABS (vsize); up = u->_mp_d; vp = v->_mp_d; rp = r->_mp_d; prec = r->_mp_prec + 1; exp = u->_mp_exp; ediff = u->_mp_exp - v->_mp_exp; /* If ediff is 0 or 1, we might have a situation where the operands are extremely close. We need to scan the operands from the most significant end ignore the initial parts that are equal. */ if (ediff <= 1) { if (ediff == 0) { /* Skip leading limbs in U and V that are equal. */ if (up[usize - 1] == vp[vsize - 1]) { /* This loop normally exits immediately. Optimize for that. */ do { usize--; vsize--; exp--; if (usize == 0) { /* u cancels high limbs of v, result is rest of v */ negate ^= 1; cancellation: /* strip high zeros before truncating to prec */ while (vsize != 0 && vp[vsize - 1] == 0) { vsize--; exp--; } if (vsize > prec) { vp += vsize - prec; vsize = prec; } MPN_COPY_INCR (rp, vp, vsize); rsize = vsize; goto done; } if (vsize == 0) { vp = up; vsize = usize; goto cancellation; } } while (up[usize - 1] == vp[vsize - 1]); } if (up[usize - 1] < vp[vsize - 1]) { /* For simplicity, swap U and V. Note that since the loop above wouldn't have exited unless up[usize - 1] and vp[vsize - 1] were non-equal, this if-statement catches all cases where U is smaller than V. */ MPN_SRCPTR_SWAP (up,usize, vp,vsize); negate ^= 1; /* negating ediff not necessary since it is 0. */ } /* Check for x+1 00000000 ... x ffffffff ... */ if (up[usize - 1] != vp[vsize - 1] + 1) goto general_case; usize--; vsize--; exp--; } else /* ediff == 1 */ { /* Check for 1 00000000 ... 0 ffffffff ... */ if (up[usize - 1] != 1 || vp[vsize - 1] != GMP_NUMB_MAX || (usize >= 2 && up[usize - 2] != 0)) goto general_case; usize--; exp--; } /* Skip sequences of 00000000/ffffffff */ while (vsize != 0 && usize != 0 && up[usize - 1] == 0 && vp[vsize - 1] == GMP_NUMB_MAX) { usize--; vsize--; exp--; } if (usize == 0) { while (vsize != 0 && vp[vsize - 1] == GMP_NUMB_MAX) { vsize--; exp--; } } if (usize > prec - 1) { up += usize - (prec - 1); usize = prec - 1; } if (vsize > prec - 1) { vp += vsize - (prec - 1); vsize = prec - 1; } tp = (mp_ptr) TMP_ALLOC (prec * BYTES_PER_MP_LIMB); { mp_limb_t cy_limb; if (vsize == 0) { mp_size_t size, i; size = usize; for (i = 0; i < size; i++) tp[i] = up[i]; tp[size] = 1; rsize = size + 1; exp++; goto normalize; } if (usize == 0) { mp_size_t size, i; size = vsize; for (i = 0; i < size; i++) tp[i] = ~vp[i] & GMP_NUMB_MASK; cy_limb = 1 - mpn_add_1 (tp, tp, vsize, (mp_limb_t) 1); rsize = vsize; if (cy_limb == 0) { tp[rsize] = 1; rsize++; exp++; } goto normalize; } if (usize >= vsize) { /* uuuu */ /* vv */ mp_size_t size; size = usize - vsize; MPN_COPY (tp, up, size); cy_limb = mpn_sub_n (tp + size, up + size, vp, vsize); rsize = usize; } else /* (usize < vsize) */ { /* uuuu */ /* vvvvvvv */ mp_size_t size, i; size = vsize - usize; for (i = 0; i < size; i++) tp[i] = ~vp[i] & GMP_NUMB_MASK; cy_limb = mpn_sub_n (tp + size, up, vp + size, usize); cy_limb+= mpn_sub_1 (tp + size, tp + size, usize, (mp_limb_t) 1); cy_limb-= mpn_add_1 (tp, tp, vsize, (mp_limb_t) 1); rsize = vsize; } if (cy_limb == 0) { tp[rsize] = 1; rsize++; exp++; } goto normalize; } } general_case: /* If U extends beyond PREC, ignore the part that does. */ if (usize > prec) { up += usize - prec; usize = prec; } /* If V extends beyond PREC, ignore the part that does. Note that this may make vsize negative. */ if (vsize + ediff > prec) { vp += vsize + ediff - prec; vsize = prec - ediff; } /* Allocate temp space for the result. Allocate just vsize + ediff later??? */ tp = (mp_ptr) TMP_ALLOC (prec * BYTES_PER_MP_LIMB); if (ediff >= prec) { /* V completely cancelled. */ if (tp != up) MPN_COPY (rp, up, usize); rsize = usize; } else { /* Locate the least significant non-zero limb in (the needed parts of) U and V, to simplify the code below. */ for (;;) { if (vsize == 0) { MPN_COPY (rp, up, usize); rsize = usize; goto done; } if (vp[0] != 0) break; vp++, vsize--; } for (;;) { if (usize == 0) { MPN_COPY (rp, vp, vsize); rsize = vsize; negate ^= 1; goto done; } if (up[0] != 0) break; up++, usize--; } /* uuuu | uuuu | uuuu | uuuu | uuuu */ /* vvvvvvv | vv | vvvvv | v | vv */ if (usize > ediff) { /* U and V partially overlaps. */ if (ediff == 0) { /* Have to compare the leading limbs of u and v to determine whether to compute u - v or v - u. */ if (usize >= vsize) { /* uuuu */ /* vv */ mp_size_t size; size = usize - vsize; MPN_COPY (tp, up, size); mpn_sub_n (tp + size, up + size, vp, vsize); rsize = usize; } else /* (usize < vsize) */ { /* uuuu */ /* vvvvvvv */ mp_size_t size, i; size = vsize - usize; tp[0] = -vp[0] & GMP_NUMB_MASK; for (i = 1; i < size; i++) tp[i] = ~vp[i] & GMP_NUMB_MASK; mpn_sub_n (tp + size, up, vp + size, usize); mpn_sub_1 (tp + size, tp + size, usize, (mp_limb_t) 1); rsize = vsize; } } else { if (vsize + ediff <= usize) { /* uuuu */ /* v */ mp_size_t size; size = usize - ediff - vsize; MPN_COPY (tp, up, size); mpn_sub (tp + size, up + size, usize - size, vp, vsize); rsize = usize; } else { /* uuuu */ /* vvvvv */ mp_size_t size, i; size = vsize + ediff - usize; tp[0] = -vp[0] & GMP_NUMB_MASK; for (i = 1; i < size; i++) tp[i] = ~vp[i] & GMP_NUMB_MASK; mpn_sub (tp + size, up, usize, vp + size, usize - ediff); mpn_sub_1 (tp + size, tp + size, usize, (mp_limb_t) 1); rsize = vsize + ediff; } } } else { /* uuuu */ /* vv */ mp_size_t size, i; size = vsize + ediff - usize; tp[0] = -vp[0] & GMP_NUMB_MASK; for (i = 1; i < vsize; i++) tp[i] = ~vp[i] & GMP_NUMB_MASK; for (i = vsize; i < size; i++) tp[i] = GMP_NUMB_MAX; mpn_sub_1 (tp + size, up, usize, (mp_limb_t) 1); rsize = size + usize; } normalize: /* Full normalize. Optimize later. */ while (rsize != 0 && tp[rsize - 1] == 0) { rsize--; exp--; } MPN_COPY (rp, tp, rsize); } done: r->_mp_size = negate ? -rsize : rsize; if (rsize == 0) exp = 0; r->_mp_exp = exp; TMP_FREE; }
static unsigned long int lc (mp_ptr rp, gmp_randstate_t rstate) { mp_ptr tp, seedp, ap; mp_size_t ta; mp_size_t tn, seedn, an; unsigned long int m2exp; unsigned long int bits; int cy; mp_size_t xn; gmp_rand_lc_struct *p; TMP_DECL; p = (gmp_rand_lc_struct *) RNG_STATE (rstate); m2exp = p->_mp_m2exp; seedp = PTR (p->_mp_seed); seedn = SIZ (p->_mp_seed); ap = PTR (p->_mp_a); an = SIZ (p->_mp_a); /* Allocate temporary storage. Let there be room for calculation of (A * seed + C) % M, or M if bigger than that. */ TMP_MARK; ta = an + seedn + 1; tn = BITS_TO_LIMBS (m2exp); if (ta <= tn) /* that is, if (ta < tn + 1) */ { mp_size_t tmp = an + seedn; ta = tn + 1; tp = (mp_ptr) TMP_ALLOC (ta * BYTES_PER_MP_LIMB); MPN_ZERO (&tp[tmp], ta - tmp); /* mpn_mul won't zero it out. */ } else tp = (mp_ptr) TMP_ALLOC (ta * BYTES_PER_MP_LIMB); /* t = a * seed. NOTE: an is always > 0; see initialization. */ ASSERT (seedn >= an && an > 0); mpn_mul (tp, seedp, seedn, ap, an); /* t = t + c. NOTE: tn is always >= p->_cn (precondition for __GMPN_ADD); see initialization. */ ASSERT (tn >= p->_cn); __GMPN_ADD (cy, tp, tp, tn, p->_cp, p->_cn); /* t = t % m */ tp[m2exp / GMP_NUMB_BITS] &= (CNST_LIMB (1) << m2exp % GMP_NUMB_BITS) - 1; /* Save result as next seed. */ MPN_COPY (PTR (p->_mp_seed), tp, tn); /* Discard the lower m2exp/2 of the result. */ bits = m2exp / 2; xn = bits / GMP_NUMB_BITS; tn -= xn; if (tn > 0) { unsigned int cnt = bits % GMP_NUMB_BITS; if (cnt != 0) { mpn_rshift (tp, tp + xn, tn, cnt); MPN_COPY_INCR (rp, tp, xn + 1); } else /* Even limb boundary. */ MPN_COPY_INCR (rp, tp + xn, tn); } TMP_FREE; /* Return number of valid bits in the result. */ return (m2exp + 1) / 2; }
static unsigned long int lc (mp_ptr rp, gmp_randstate_t rstate) { mp_ptr tp, seedp, ap; mp_size_t ta; mp_size_t tn, seedn, an; unsigned long int m2exp; mp_limb_t c; TMP_DECL (mark); m2exp = rstate->_mp_algdata._mp_lc->_mp_m2exp; /* The code below assumes the mod part is a power of two. Make sure that is the case. */ ASSERT_ALWAYS (m2exp != 0); c = (mp_limb_t) rstate->_mp_algdata._mp_lc->_mp_c; seedp = PTR (rstate->_mp_seed); seedn = SIZ (rstate->_mp_seed); if (seedn == 0) { /* Seed is 0. Result is C % M. Assume table is sensibly stored, with C smaller than M*/ *rp = c; *seedp = c; SIZ (rstate->_mp_seed) = 1; return m2exp; } ap = PTR (rstate->_mp_algdata._mp_lc->_mp_a); an = SIZ (rstate->_mp_algdata._mp_lc->_mp_a); /* Allocate temporary storage. Let there be room for calculation of (A * seed + C) % M, or M if bigger than that. */ TMP_MARK (mark); ta = an + seedn + 1; tp = (mp_ptr) TMP_ALLOC (ta * BYTES_PER_MP_LIMB); /* t = a * seed */ if (seedn >= an) mpn_mul (tp, seedp, seedn, ap, an); else mpn_mul (tp, ap, an, seedp, seedn); tn = an + seedn; /* t = t + c */ tp[tn] = 0; /* sentinel, stops MPN_INCR_U */ MPN_INCR_U (tp, tn, c); ASSERT_ALWAYS (m2exp / GMP_NUMB_BITS < ta); /* t = t % m */ tp[m2exp / GMP_NUMB_BITS] &= ((mp_limb_t) 1 << m2exp % GMP_NUMB_BITS) - 1; tn = (m2exp + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS; /* Save result as next seed. */ MPN_COPY (PTR (rstate->_mp_seed), tp, tn); SIZ (rstate->_mp_seed) = tn; { /* Discard the lower m2exp/2 bits of result. */ unsigned long int bits = m2exp / 2; mp_size_t xn = bits / GMP_NUMB_BITS; tn -= xn; if (tn > 0) { unsigned int cnt = bits % GMP_NUMB_BITS; if (cnt != 0) { mpn_rshift (tp, tp + xn, tn, cnt); MPN_COPY_INCR (rp, tp, xn + 1); } else /* Even limb boundary. */ MPN_COPY_INCR (rp, tp + xn, tn); } } TMP_FREE (mark); /* Return number of valid bits in the result. */ return (m2exp + 1) / 2; }
void mpf_mul_2exp (mpf_ptr r, mpf_srcptr u, mp_bitcnt_t exp) { mp_srcptr up; mp_ptr rp = r->_mp_d; mp_size_t usize; mp_size_t abs_usize; mp_size_t prec = r->_mp_prec; mp_exp_t uexp = u->_mp_exp; usize = u->_mp_size; if (UNLIKELY (usize == 0)) { r->_mp_size = 0; r->_mp_exp = 0; return; } abs_usize = ABS (usize); up = u->_mp_d; if (exp % GMP_NUMB_BITS == 0) { prec++; /* retain more precision here as we don't need to account for carry-out here */ if (abs_usize > prec) { up += abs_usize - prec; abs_usize = prec; } if (rp != up) MPN_COPY_INCR (rp, up, abs_usize); r->_mp_exp = uexp + exp / GMP_NUMB_BITS; } else { mp_limb_t cy_limb; mp_size_t adj; if (abs_usize > prec) { up += abs_usize - prec; abs_usize = prec; /* Use mpn_rshift since mpn_lshift operates downwards, and we therefore would clobber part of U before using that part, in case R is the same variable as U. */ cy_limb = mpn_rshift (rp + 1, up, abs_usize, GMP_NUMB_BITS - exp % GMP_NUMB_BITS); rp[0] = cy_limb; adj = rp[abs_usize] != 0; } else { cy_limb = mpn_lshift (rp, up, abs_usize, exp % GMP_NUMB_BITS); rp[abs_usize] = cy_limb; adj = cy_limb != 0; } abs_usize += adj; r->_mp_exp = uexp + exp / GMP_NUMB_BITS + adj; } r->_mp_size = usize >= 0 ? abs_usize : -abs_usize; }
void mpf_add (mpf_ptr r, mpf_srcptr u, mpf_srcptr v) { mp_srcptr up, vp; mp_ptr rp, tp; mp_size_t usize, vsize, rsize; mp_size_t prec; mp_exp_t uexp; mp_size_t ediff; mp_limb_t cy; int negate; TMP_DECL (marker); usize = u->_mp_size; vsize = v->_mp_size; /* Handle special cases that don't work in generic code below. */ if (usize == 0) { set_r_v_maybe: if (r != v) mpf_set (r, v); return; } if (vsize == 0) { v = u; goto set_r_v_maybe; } /* If signs of U and V are different, perform subtraction. */ if ((usize ^ vsize) < 0) { __mpf_struct v_negated; v_negated._mp_size = -vsize; v_negated._mp_exp = v->_mp_exp; v_negated._mp_d = v->_mp_d; mpf_sub (r, u, &v_negated); return; } TMP_MARK (marker); /* Signs are now known to be the same. */ negate = usize < 0; /* Make U be the operand with the largest exponent. */ if (u->_mp_exp < v->_mp_exp) { mpf_srcptr t; t = u; u = v; v = t; usize = u->_mp_size; vsize = v->_mp_size; } usize = ABS (usize); vsize = ABS (vsize); up = u->_mp_d; vp = v->_mp_d; rp = r->_mp_d; prec = r->_mp_prec; uexp = u->_mp_exp; ediff = u->_mp_exp - v->_mp_exp; /* If U extends beyond PREC, ignore the part that does. */ if (usize > prec) { up += usize - prec; usize = prec; } /* If V extends beyond PREC, ignore the part that does. Note that this may make vsize negative. */ if (vsize + ediff > prec) { vp += vsize + ediff - prec; vsize = prec - ediff; } #if 0 /* Locate the least significant non-zero limb in (the needed parts of) U and V, to simplify the code below. */ while (up[0] == 0) up++, usize--; while (vp[0] == 0) vp++, vsize--; #endif /* Allocate temp space for the result. Allocate just vsize + ediff later??? */ tp = (mp_ptr) TMP_ALLOC (prec * BYTES_PER_MP_LIMB); if (ediff >= prec) { /* V completely cancelled. */ if (rp != up) MPN_COPY_INCR (rp, up, usize); rsize = usize; } else { /* uuuu | uuuu | uuuu | uuuu | uuuu */ /* vvvvvvv | vv | vvvvv | v | vv */ if (usize > ediff) { /* U and V partially overlaps. */ if (vsize + ediff <= usize) { /* uuuu */ /* v */ mp_size_t size; size = usize - ediff - vsize; MPN_COPY (tp, up, size); cy = mpn_add (tp + size, up + size, usize - size, vp, vsize); rsize = usize; } else { /* uuuu */ /* vvvvv */ mp_size_t size; size = vsize + ediff - usize; MPN_COPY (tp, vp, size); cy = mpn_add (tp + size, up, usize, vp + size, usize - ediff); rsize = vsize + ediff; } } else { /* uuuu */ /* vv */ mp_size_t size; size = vsize + ediff - usize; MPN_COPY (tp, vp, vsize); MPN_ZERO (tp + vsize, ediff - usize); MPN_COPY (tp + size, up, usize); cy = 0; rsize = size + usize; } MPN_COPY (rp, tp, rsize); rp[rsize] = cy; rsize += cy; uexp += cy; } r->_mp_size = negate ? -rsize : rsize; r->_mp_exp = uexp; TMP_FREE (marker); }
void mpn_copyi(mp_ptr rp,mp_srcptr sp,mp_size_t n) { MPN_COPY_INCR(rp,sp,n); return; }
mp_limb_t mpn_preinv_dc_divappr_q (mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn, mp_srcptr dip) { mp_size_t qn; mp_limb_t qh, cy, qsave; mp_ptr tp; TMP_DECL; TMP_MARK; tp = TMP_SALLOC_LIMBS (dn+1); qn = nn - dn; qp += qn; np += nn; dp += dn; if (qn > dn) { qn++; /* pretend we'll need an extra limb */ /* Reduce qn mod dn without division, optimizing small operations. */ do qn -= dn; while (qn > dn); qp -= qn; /* point at low limb of next quotient block */ np -= qn; /* point in the middle of partial remainder */ /* Perform the typically smaller block first. */ if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD)) qh = mpn_sb_div_qr (qp, np - qn, 2 * qn, dp - qn, qn, dip); else qh = mpn_dc_div_qr_n (qp, np - qn, dp - qn, qn, dip, tp); if (qn != dn) { if (qn > dn - qn) mpn_mul (tp, qp, qn, dp - dn, dn - qn); else mpn_mul (tp, dp - dn, dn - qn, qp, qn); cy = mpn_sub_n (np - dn, np - dn, tp, dn); if (qh != 0) cy += mpn_sub_n (np - dn + qn, np - dn + qn, dp - dn, dn - qn); while (cy != 0) { qh -= mpn_sub_1 (qp, qp, qn, 1); cy -= mpn_add_n (np - dn, np - dn, dp - dn, dn); } } qn = nn - dn - qn + 1; while (qn > dn) { qp -= dn; np -= dn; mpn_dc_div_qr_n (qp, np - dn, dp - dn, dn, dip, tp); qn -= dn; } /* Since we pretended we'd need an extra quotient limb before, we now have made sure the code above left just dn-1=qn quotient limbs to develop. Develop that plus a guard limb. */ qn--; qp -= qn; np -= dn; qsave = qp[qn]; mpn_dc_divappr_q_n (qp, np - dn, dp - dn, dn, dip, tp); MPN_COPY_INCR (qp, qp + 1, qn); qp[qn] = qsave; } else { if (qn == 0) { qh = mpn_cmp (np - dn, dp - dn, dn) >= 0; if (qh) mpn_sub_n (np - dn, np - dn, dp - dn, dn); TMP_FREE; return qh; } qp -= qn; /* point at low limb of next quotient block */ np -= qn; /* point in the middle of partial remainder */ if (BELOW_THRESHOLD (qn, DC_DIVAPPR_Q_THRESHOLD)) /* Full precision. Optimal? */ qh = mpn_sb_divappr_q (qp, np - dn, nn, dp - dn, dn, dip); else { /* Put quotient in tp, use qp as temporary, since qp lacks a limb. */ qh = mpn_dc_divappr_q_n (tp, np - qn - 2, dp - (qn + 1), qn + 1, dip, qp); MPN_COPY (qp, tp + 1, qn); } } TMP_FREE; return qh; }
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 } }