void mpf_ui_sub (mpf_ptr r, unsigned long int u, mpf_srcptr v) { #if 1 __mpf_struct uu; mp_limb_t ul; if (u == 0) { mpf_neg (r, v); return; } ul = u; uu._mp_size = 1; uu._mp_d = &ul; uu._mp_exp = 1; mpf_sub (r, &uu, v); #else 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; int negate; mp_limb_t ulimb; TMP_DECL; vsize = v->_mp_size; /* Handle special cases that don't work in generic code below. */ if (u == 0) { mpf_neg (r, v); return; } if (vsize == 0) { mpf_set_ui (r, u); return; } /* If signs of U and V are different, perform addition. */ if (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_ui (r, &v_negated, u); return; } /* Signs are now known to be the same. */ ASSERT (vsize > 0); ulimb = u; /* Make U be the operand with the largest exponent. */ negate = 1 < v->_mp_exp; prec = r->_mp_prec + negate; rp = r->_mp_d; if (negate) { usize = vsize; vsize = 1; up = v->_mp_d; vp = &ulimb; uexp = v->_mp_exp; ediff = uexp - 1; /* If U extends beyond PREC, ignore the part that does. */ if (usize > prec) { up += usize - prec; usize = prec; } ASSERT (ediff > 0); } else { vp = v->_mp_d; ediff = 1 - v->_mp_exp; /* Ignore leading limbs in U and V that are equal. Doing this helps increase the precision of the result. */ if (ediff == 0 && ulimb == vp[vsize - 1]) { usize = 0; vsize--; uexp = 0; /* Note that V might now have leading zero limbs. In that case we have to adjust uexp. */ for (;;) { if (vsize == 0) { rsize = 0; uexp = 0; goto done; } if ( vp[vsize - 1] != 0) break; vsize--, uexp--; } } else { usize = 1; uexp = 1; up = &ulimb; } ASSERT (usize <= prec); } if (ediff >= prec) { /* V completely cancelled. */ if (rp != up) MPN_COPY (rp, up, usize); rsize = usize; } else { /* If V extends beyond PREC, ignore the part that does. Note that this can make vsize neither zero nor negative. */ if (vsize + ediff > prec) { vp += vsize + ediff - prec; vsize = prec - ediff; } /* Locate the least significant non-zero limb in (the needed parts of) U and V, to simplify the code below. */ ASSERT (vsize > 0); for (;;) { if (vp[0] != 0) break; vp++, vsize--; if (vsize == 0) { MPN_COPY (rp, up, usize); rsize = usize; goto done; } } for (;;) { if (usize == 0) { MPN_COPY (rp, vp, vsize); rsize = vsize; negate ^= 1; goto done; } if (up[0] != 0) break; up++, usize--; } ASSERT (usize > 0 && vsize > 0); TMP_MARK; tp = TMP_ALLOC_LIMBS (prec); /* uuuu | uuuu | uuuu | uuuu | uuuu */ /* vvvvvvv | vv | vvvvv | v | vv */ if (usize > ediff) { /* U and V partially overlaps. */ if (ediff == 0) { ASSERT (usize == 1 && vsize >= 1 && ulimb == *up); /* usize is 1>ediff, vsize >= 1 */ if (1 < vsize) { /* u */ /* vvvvvvv */ rsize = vsize; vsize -= 1; /* mpn_cmp (up, vp + vsize - usize, usize) > 0 */ if (ulimb > vp[vsize]) { tp[vsize] = ulimb - vp[vsize] - 1; ASSERT_CARRY (mpn_neg (tp, vp, vsize)); } else { /* vvvvvvv */ /* Swap U and V. */ /* u */ MPN_COPY (tp, vp, vsize); tp[vsize] = vp[vsize] - ulimb; negate = 1; } } else /* vsize == usize == 1 */ { /* u */ /* v */ rsize = 1; negate = ulimb < vp[0]; tp[0] = negate ? vp[0] - ulimb: ulimb - vp[0]; } } else { ASSERT (vsize + ediff <= usize); ASSERT (vsize == 1 && usize >= 2 && ulimb == *vp); { /* uuuu */ /* v */ mp_size_t size; size = usize - ediff - 1; MPN_COPY (tp, up, size); ASSERT_NOCARRY (mpn_sub_1 (tp + size, up + size, usize - size, ulimb)); rsize = usize; } /* Other cases are not possible */ /* uuuu */ /* vvvvv */ } } else { /* uuuu */ /* vv */ mp_size_t size, i; ASSERT_CARRY (mpn_neg (tp, vp, vsize)); rsize = vsize + ediff; size = rsize - usize; for (i = vsize; i < size; i++) tp[i] = GMP_NUMB_MAX; ASSERT_NOCARRY (mpn_sub_1 (tp + size, up, usize, CNST_LIMB (1))); } /* Full normalize. Optimize later. */ while (rsize != 0 && tp[rsize - 1] == 0) { rsize--; uexp--; } MPN_COPY (rp, tp, rsize); TMP_FREE; } done: r->_mp_size = negate ? -rsize : rsize; r->_mp_exp = uexp; #endif }
mp_limb_t mpn_divrem_euclidean_qr_2(mp_ptr qp, mp_ptr xp, mp_size_t xn, mp_srcptr dp) { mp_size_t qn; mp_limb_t qf, t[2], t1[2], q, h, l, d1, d2, i; int c1, c3, c4; ASSERT(xn >= 2); ASSERT_MPN(dp, 2); ASSERT_MPN(xp, xn); ASSERT(dp[1] != 0); qn = xn - 1; /* ASSERT(!MPN_OVERLAP_P(qp, qn, xp, xn)); */ /* FIXME: correct this overlap requirement */ ASSERT((dp[1]>>(GMP_NUMB_BITS - 1)) != 0); h = 0; d1 = dp[1]; d2 = dp[0]; invert_limb(i, d1); l = xp[xn - 1]; qn = xn - 2; t[0] = xp[qn]; if (l < d1) { h = t[1] = l; l = t[0] = xp[qn]; qf = 0; } else { qf = 1; t[1] = l - d1; t1[1] = 0; t1[0] = d2; if (mpn_sub_n(t, t, t1, 2)) { qf--; mpn_add_n(t, t, dp, 2); } h = t[1]; l = t[0]; } for (qn = xn - 3; qn >= 0; qn--) { t[0] = xp[qn]; if (h < d1) { udiv_qrnnd_preinv(q, t[1], h, l, d1, i); umul_ppmm(t1[1], t1[0], q, d2); if (mpn_sub_n(t, t, t1, 2)) { q--; if (mpn_add_n(t, t, dp, 2) == 0) { q--; ASSERT_CARRY(mpn_add_n(t, t, dp, 2)); } } } else { ASSERT(h == d1); q = -1; t[1] = l; c3 = mpn_add_n(t, t, dp, 2); c1 = mpn_sub_1(t + 1, t + 1, 1, d2); c4 = c3 - c1; if (l >= d1) { ASSERT(c3 != 0); ASSERT(c4 == 0); } /* our guess is B + 1, so q = B - 1 is correct */ else { ASSERT(c4 <= 0); /* our guess is B so q = B - 1 or B - 2 */ if (c4 != 0) { q--; mpn_add_n(t, t, dp, 2); } } } h = t[1]; l = t[0]; qp[qn] = q; } xp[1] = t[1]; xp[0] = t[0]; return qf; }