void fmpz_tdiv(fmpz_t res, const fmpz_t a, const fmpz_t b) { long a0 = a[0]; long b0 = b[0]; unsigned long sizea = FLINT_ABS(a0); unsigned long sizeb = FLINT_ABS(b0); while ((!a[sizea]) && (sizea)) sizea--; while ((!b[sizeb]) && (sizeb)) sizeb--; mp_limb_t mslimb; fmpz_t temp; if (sizeb == 0) { printf("Error: division by zero!\n"); abort(); } else if (sizea < sizeb) // Todo: make this deal with sizea == sizeb but a < b { res[0] = 0; } else { temp = (fmpz_t) flint_stack_alloc(sizeb); mpn_tdiv_qr(res+1, temp, 0, a+1, sizea, b+1, sizeb); res[0] = sizea - sizeb + 1; if ((long) (a0 ^ b0) < 0) res[0] = -res[0]; flint_stack_release(); } NORM(res); }
void mpfq_p_127_735_field_init(mpfq_p_127_735_dst_field k, mp_limb_t *p) { k->p = (mp_limb_t *)malloc(2*sizeof(mp_limb_t)); k->bigmul_p = (mp_limb_t *)malloc(5*sizeof(mp_limb_t)); if ((!k->p) || (!k->bigmul_p)) MALLOC_FAILED(); { int i; k->p[0] = -735UL; for (i = 1; i < (2-1); ++i) k->p[i] = -1UL; k->p[2-1] = (-1UL) >> 1; // 2^(w-1) - 1 where w is 32 or 64 } k->kl = 2; k->url = 5; k->url_margin = LONG_MAX; k->type = CLASSICAL_REP; mpz_init(k->factor); // precompute bigmul_p = largest multiple of p that fits in an elt_ur // p*Floor( (2^(5*GMP_LIMB_BITS)-1)/p ) { mpfq_p_127_735_elt_ur big; mp_limb_t q[5-2+1], r[2], tmp[5+1]; int i; for (i = 0; i < 5; ++i) big[i] = ~0UL; mpn_tdiv_qr(q, r, 0, big, 5, k->p, 2); mpn_mul(tmp, q, 5-2+1, k->p, 2); for (i = 0; i < 5; ++i) (k->bigmul_p)[i] = tmp[i]; assert (tmp[5] == 0UL); } }
void fp_invn_low(dig_t *c, const dig_t *a) { mp_size_t cn; align dig_t s[FP_DIGS], t[2 * FP_DIGS], u[FP_DIGS + 1]; #if FP_RDC == MONTY dv_zero(t + FP_DIGS, FP_DIGS); dv_copy(t, a, FP_DIGS); fp_rdcn_low(u, t); #else fp_copy(u, a); #endif dv_copy(s, fp_prime_get(), FP_DIGS); mpn_gcdext(t, c, &cn, u, FP_DIGS, s, FP_DIGS); if (cn < 0) { dv_zero(c - cn, FP_DIGS + cn); mpn_sub_n(c, fp_prime_get(), c, FP_DIGS); } else { dv_zero(c + cn, FP_DIGS - cn); } #if FP_RDC == MONTY dv_zero(t, FP_DIGS); dv_copy(t + FP_DIGS, c, FP_DIGS); mpn_tdiv_qr(u, c, 0, t, 2 * FP_DIGS, fp_prime_get(), FP_DIGS); #endif }
unsigned long int mpz_cdiv_qr_ui (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor) { mp_size_t ns, nn, qn; mp_ptr np, qp; mp_limb_t rl; if (divisor == 0) DIVIDE_BY_ZERO; ns = SIZ(dividend); if (ns == 0) { SIZ(quot) = 0; SIZ(rem) = 0; return 0; } nn = ABS(ns); MPZ_REALLOC (quot, nn); qp = PTR(quot); np = PTR(dividend); #if GMP_NAIL_BITS != 0 if (divisor > GMP_NUMB_MAX) { mp_limb_t dp[2]; mp_ptr rp; mp_size_t rn; MPZ_REALLOC (rem, 2); rp = PTR(rem); if (nn == 1) /* tdiv_qr requirements; tested above for 0 */ { qp[0] = 0; qn = 1; /* a white lie, fixed below */ rl = np[0]; rp[0] = rl; } else { dp[0] = divisor & GMP_NUMB_MASK; dp[1] = divisor >> GMP_NUMB_BITS; mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2); rl = rp[0] + (rp[1] << GMP_NUMB_BITS); qn = nn - 2 + 1; } if (rl != 0 && ns >= 0) { mpn_incr_u (qp, (mp_limb_t) 1); rl = divisor - rl; rp[0] = rl & GMP_NUMB_MASK; rp[1] = rl >> GMP_NUMB_BITS; }
/* Truncating (i.e. rounded towards zero) integer division-quotient of MPN */ void integer_gmp_mpn_tdiv_q (mp_limb_t q[], const mp_limb_t n[], const mp_size_t nn, const mp_limb_t d[], const mp_size_t dn) { /* qn = 1+nn-dn; rn = dn */ assert(nn>=dn); if (dn > 128) { // Use temporary heap allocated throw-away buffer for MPNs larger // than 1KiB for 64bit-sized limbs (larger than 512bytes for // 32bit-sized limbs) mp_limb_t *const r = malloc(dn*sizeof(mp_limb_t)); mpn_tdiv_qr(q, r, 0, n, nn, d, dn); free (r); } else { // allocate smaller arrays on the stack mp_limb_t r[dn]; mpn_tdiv_qr(q, r, 0, n, nn, d, dn); } }
void Sqr(modp& ans,const modp& x,const Zp_Data& ZpD) { if (ZpD.montgomery) { ZpD.Mont_Mult(ans.x,x.x,x.x); } else { //ans.x=(x.x*x.x)%ZpD.pr; mp_limb_t aa[2*MAX_MOD_SZ],q[2*MAX_MOD_SZ]; mpn_sqr(aa,x.x,ZpD.t); mpn_tdiv_qr(q,ans.x,0,aa,2*ZpD.t,ZpD.prA,ZpD.t); } }
/* Convert U to REDC form, U_r = B^n * U mod M */ static void redcify (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr mp, mp_size_t n, mp_ptr tp) { mp_ptr qp; qp = tp + un + n; MPN_ZERO (tp, n); MPN_COPY (tp + n, up, un); mpn_tdiv_qr (qp, rp, 0L, tp, un + n, mp, n); }
static void fp_mul_si(element_ptr e, element_ptr a, signed long int op) { fp_field_data_ptr p = e->field->data; size_t t = p->limbs; mp_limb_t *tmp = _alloca((t + 1) * sizeof(mp_limb_t)); mp_limb_t qp[2]; tmp[t] = mpn_mul_1(tmp, a->data, t, labs(op)); mpn_tdiv_qr(qp, e->data, 0, tmp, t + 1, p->primelimbs, t); if (op < 0) { fp_neg(e, e); } }
unsigned long int mpz_fdiv_r_ui (mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor) { mp_size_t ns, nn; mp_ptr np; mp_limb_t rl; if (divisor == 0) DIVIDE_BY_ZERO; ns = SIZ(dividend); if (ns == 0) { SIZ(rem) = 0; return 0; } nn = ABS(ns); np = PTR(dividend); #if BITS_PER_ULONG > GMP_NUMB_BITS /* avoid warnings about shift amount */ if (divisor > GMP_NUMB_MAX) { mp_limb_t dp[2]; mp_ptr rp, qp; mp_size_t rn; TMP_DECL; MPZ_REALLOC (rem, 2); rp = PTR(rem); if (nn == 1) /* tdiv_qr requirements; tested above for 0 */ { rl = np[0]; rp[0] = rl; } else { TMP_MARK; dp[0] = divisor & GMP_NUMB_MASK; dp[1] = divisor >> GMP_NUMB_BITS; qp = TMP_ALLOC_LIMBS (nn - 2 + 1); mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2); TMP_FREE; rl = rp[0] + (rp[1] << GMP_NUMB_BITS); } if (rl != 0 && ns < 0) { rl = divisor - rl; rp[0] = rl & GMP_NUMB_MASK; rp[1] = rl >> GMP_NUMB_BITS; }
/* Compute t = a mod m, a is defined by (ap,an), m is defined by (mp,mn), and t is defined by (tp,mn). */ static void reduce (mp_ptr tp, mp_srcptr ap, mp_size_t an, mp_srcptr mp, mp_size_t mn) { mp_ptr qp; TMP_DECL; TMP_MARK; qp = TMP_ALLOC_LIMBS (an - mn + 1); mpn_tdiv_qr (qp, tp, 0L, ap, an, mp, mn); TMP_FREE; }
mpir_ui mpz_fdiv_q_ui (mpz_ptr quot, mpz_srcptr dividend, mpir_ui divisor) { mp_size_t ns, nn, qn; mp_ptr np, qp; mp_limb_t rl; if (divisor == 0) DIVIDE_BY_ZERO; ns = SIZ(dividend); if (ns == 0) { SIZ(quot) = 0; return 0; } nn = ABS(ns); MPZ_REALLOC (quot, nn); qp = PTR(quot); np = PTR(dividend); #if BITS_PER_UI > GMP_NUMB_BITS /* avoid warnings about shift amount */ if (divisor > GMP_NUMB_MAX) { mp_limb_t dp[2], rp[2]; if (nn == 1) /* tdiv_qr requirements; tested above for 0 */ { qp[0] = 0; rl = np[0]; qn = 1; /* a white lie, fixed below */ } else { dp[0] = divisor & GMP_NUMB_MASK; dp[1] = divisor >> GMP_NUMB_BITS; mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2); rl = rp[0] + (rp[1] << GMP_NUMB_BITS); qn = nn - 2 + 1; } if (rl != 0 && ns < 0) { mpn_incr_u (qp, (mp_limb_t) 1); rl = divisor - rl; } qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0; }
static void fp_mul(element_ptr c, element_ptr a, element_ptr b) { fp_field_data_ptr p = c->field->data; size_t t = p->limbs; //mp_limb_t tmp[3 * t + 1]; //mp_limb_t *qp = &tmp[2 * t]; mp_limb_t *tmp = _alloca(2 * t * sizeof(mp_limb_t)); mp_limb_t *qp = _alloca((t + 1) * sizeof(mp_limb_t)); //static mp_limb_t tmp[2 * 100]; //static mp_limb_t qp[100 + 1]; mpn_mul_n(tmp, a->data, b->data, t); mpn_tdiv_qr(qp, c->data, 0, tmp, 2 * t, p->primelimbs, t); }
mpir_ui mpz_tdiv_qr_ui (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, mpir_ui divisor) { mp_size_t ns, nn, qn; mp_ptr np, qp; mp_limb_t rl; if (divisor == 0) DIVIDE_BY_ZERO; ns = SIZ(dividend); if (ns == 0) { SIZ(quot) = 0; SIZ(rem) = 0; return 0; } nn = ABS(ns); MPZ_REALLOC (quot, nn); qp = PTR(quot); np = PTR(dividend); #if BITS_PER_UI > GMP_NUMB_BITS /* avoid warnings about shift amount */ if (divisor > GMP_NUMB_MAX) { mp_limb_t dp[2]; mp_ptr rp; mp_size_t rn; if (nn == 1) /* tdiv_qr requirements; tested above for 0 */ { SIZ(quot) = 0; rl = np[0]; SIZ(rem) = ns >= 0 ? 1 : -1; PTR(rem)[0] = rl; return rl; } MPZ_REALLOC (rem, 2); rp = PTR(rem); dp[0] = divisor & GMP_NUMB_MASK; dp[1] = divisor >> GMP_NUMB_BITS; mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2); rl = rp[0] + (rp[1] << GMP_NUMB_BITS); qn = nn - 2 + 1; qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0; rn = 2 - (rp[1] == 0); rn -= (rp[rn - 1] == 0); SIZ(rem) = ns >= 0 ? rn : -rn; }
/* Convert U to REDC form, U_r = B^n * U mod M */ static void redcify (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr mp, mp_size_t n) { mp_ptr tp, qp; TMP_DECL; TMP_MARK; tp = TMP_ALLOC_LIMBS (un + n); qp = TMP_ALLOC_LIMBS (un + 1); /* FIXME: Put at tp+? */ MPN_ZERO (tp, n); MPN_COPY (tp + n, up, un); mpn_tdiv_qr (qp, rp, 0L, tp, un + n, mp, n); TMP_FREE; }
void gmp_wrap_sb_div_rem(char * n1l, char * n2l, char * quol, char * reml) { WORD_PTR_TYPE n1 = TO_WORD_PTR(n1l); mp_size_t l1 = BIGNUM_LENGTH(n1); WORD_PTR_TYPE n2 = TO_WORD_PTR(n2l); mp_size_t l2 = BIGNUM_LENGTH(n2); WORD_PTR_TYPE quo = TO_WORD_PTR(quol); WORD_PTR_TYPE rem = TO_WORD_PTR(reml); mp_size_t lr = BIGNUM_LENGTH(rem); if (n2[l2 - 1] == 0) { l2 = l2 - 1; rem[lr - 1] = 0; } mpn_tdiv_qr(quo, rem, 0, n1, l1, n2, l2); }
void fmpz_fdiv(fmpz_t res, const fmpz_t a, const fmpz_t b) { long a0 = a[0]; long b0 = b[0]; unsigned long sizea = FLINT_ABS(a0); unsigned long sizeb = FLINT_ABS(b0); while ((!a[sizea]) && (sizea)) sizea--; while ((!b[sizeb]) && (sizeb)) sizeb--; mp_limb_t mslimb; fmpz_t temp; if (sizeb == 0) { printf("Error: division by zero!\n"); abort(); } else if (sizea < sizeb) // Todo: make this deal with sizea == sizeb but a < b { if (((long) (a0 ^ b0) < 0L) && (a0)) { res[0] = -1L; res[1] = 1; } else res[0] = 0; return; } else { temp = (fmpz_t) flint_stack_alloc(sizeb); mpn_tdiv_qr(res+1, temp, 0, a+1, sizea, b+1, sizeb); res[0] = sizea - sizeb + 1; if ((long) (a0 ^ b0) < 0L) res[0] = -res[0]; NORM(res); if ((long) (a0 ^ b0) < 0L) { unsigned long i = 0; for (; i < sizeb; i++) { if (temp[i]) break; } if (i < sizeb) { fmpz_sub_ui_inplace(res, 1UL); } } flint_stack_release(); } }
void *VectMul (void *th) { long Tid = (long) th; // interleaving communication with computation if (Tid == NCORES-1) // this thread handles communication { if (id == 0) { MPI_Isend (v3[BLOCK_LOW(id,p,VLEN)], BLOCK_SIZE(id,p,VLEN), mpntype1, id^1, 0, MPI_COMM_WORLD, &Srqst); MPI_Irecv (v3[BLOCK_LOW(id^1,p,VLEN)], BLOCK_SIZE(id^1,p,VLEN), mpntype1, id^1, 1, MPI_COMM_WORLD, &Rrqst); } else if (id == 1) { MPI_Isend (v3[BLOCK_LOW(id,p,VLEN)], BLOCK_SIZE(id,p,VLEN), mpntype1, id^1, 1, MPI_COMM_WORLD, &Srqst); MPI_Irecv (v3[BLOCK_LOW(id^1,p,VLEN)], BLOCK_SIZE(id^1,p,VLEN), mpntype1, id^1, 0, MPI_COMM_WORLD, &Rrqst); } } else if (Tid < NCORES-1) // these threads handle computation { vectvectmul (v1, v2, Tid); // product of two vectors // reduction within a node using threads pthread_mutex_lock (&mutexvv); mpn_add_n (fin_sum, fin_sum, temp_sum[Tid], 2*LIMBS+1); pthread_mutex_unlock (&mutexvv); // each thread waits for every other thread to finish reduction wait (NCORES-1); // reduction across nodes using MPI if (Tid == 0) { MPI_Allreduce (fin_sum, result, 1, mpntype0, mpn_sum, MPI_COMM_WORLD); mpn_tdiv_qr (tquo, cnum, 0, result, 2*LIMBS+1, q, LIMBS); } wait (NCORES-1); } if (Tid == NCORES-1) // waiting for the communications to terminate { MPI_Wait (&Srqst, &Sstatus); MPI_Wait (&Rrqst, &Rstatus); } }
unsigned long int mpz_tdiv_ui (mpz_srcptr dividend, unsigned long int divisor) { mp_size_t ns, nn; mp_ptr np; mp_limb_t rl; if (divisor == 0) DIVIDE_BY_ZERO; ns = SIZ(dividend); if (ns == 0) { return 0; } nn = ABS(ns); np = PTR(dividend); #if BITS_PER_ULONG > GMP_NUMB_BITS /* avoid warnings about shift amount */ if (divisor > GMP_NUMB_MAX) { mp_limb_t dp[2], rp[2]; mp_ptr qp; mp_size_t rn; TMP_DECL; if (nn == 1) /* tdiv_qr requirements; tested above for 0 */ { rl = np[0]; return rl; } TMP_MARK; dp[0] = divisor & GMP_NUMB_MASK; dp[1] = divisor >> GMP_NUMB_BITS; qp = TMP_ALLOC_LIMBS (nn - 2 + 1); mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2); TMP_FREE; rl = rp[0] + (rp[1] << GMP_NUMB_BITS); rn = 2 - (rp[1] == 0); rn -= (rp[rn - 1] == 0); }
unsigned long int mpz_tdiv_q_ui (mpz_ptr quot, mpz_srcptr dividend, unsigned long int divisor) { mp_size_t ns, nn, qn; mp_ptr np, qp; mp_limb_t rl; if (divisor == 0) DIVIDE_BY_ZERO; ns = SIZ(dividend); if (ns == 0) { SIZ(quot) = 0; return 0; } nn = ABS(ns); MPZ_REALLOC (quot, nn); qp = PTR(quot); np = PTR(dividend); #if BITS_PER_ULONG > GMP_NUMB_BITS /* avoid warnings about shift amount */ if (divisor > GMP_NUMB_MAX) { mp_limb_t dp[2], rp[2]; if (nn == 1) /* tdiv_qr requirements; tested above for 0 */ { SIZ(quot) = 0; rl = np[0]; return rl; } dp[0] = divisor & GMP_NUMB_MASK; dp[1] = divisor >> GMP_NUMB_BITS; mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2); rl = rp[0] + (rp[1] << GMP_NUMB_BITS); qn = nn - 2 + 1; qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0; }
void gcdext_get_t(mp_ptr t, mp_size_t * tn, mp_ptr gp, mp_size_t gn, mp_ptr ap, mp_size_t an, mp_ptr bp, mp_size_t n, mp_ptr s, mp_size_t sn, mp_ptr tp) { mp_size_t ss = ABS(sn); mp_limb_t cy; if (ss >= an) mpn_mul(tp, s, ss, ap, an); else mpn_mul(tp, ap, an, s, ss); (*tn) = ss + an; (*tn) -= (tp[(*tn) - 1] == 0); /* We must have s*ap >= gp and we really want to compute -t */ if (sn > 0) { mpn_sub(tp, tp, *tn, gp, gn); MPN_NORMALIZE(tp, (*tn)); } else { cy = mpn_add(tp, tp, *tn, gp, gn); if (cy) tp[(*tn)++] = cy; } if ((*tn) == 0) { return; } mpn_tdiv_qr(t, tp, 0, tp, (*tn), bp, n); ASSERT_MPN_ZERO_P(tp, n); (*tn) -= (n - 1); (*tn) -= (t[(*tn) - 1] == 0); }
void mpn_invert (mp_ptr ip, mp_srcptr dp, mp_size_t n, mp_ptr scratch) { mp_ptr np, rp; mp_size_t i; TMP_DECL; TMP_MARK; if (scratch == NULL) { scratch = TMP_ALLOC_LIMBS (mpn_invert_itch (n)); } np = scratch; /* 2 * n limbs */ rp = scratch + 2 * n; /* n + 2 limbs */ for (i = n - 1; i >= 0; i--) np[i] = ~CNST_LIMB(0); mpn_com_n (np + n, dp, n); mpn_tdiv_qr (rp, ip, 0L, np, 2 * n, dp, n); MPN_COPY (ip, rp, n); TMP_FREE; }
void mpz_powm_ui (mpz_ptr r, mpz_srcptr b, unsigned long int el, mpz_srcptr m) { mp_ptr xp, tp, qp, mp, bp; mp_size_t xn, tn, mn, bn; int m_zero_cnt; int c; mp_limb_t e; TMP_DECL; mp = PTR(m); mn = ABSIZ(m); if (mn == 0) DIVIDE_BY_ZERO; if (el == 0) { /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0 depending on if MOD equals 1. */ SIZ(r) = (mn == 1 && mp[0] == 1) ? 0 : 1; PTR(r)[0] = 1; return; } TMP_MARK; /* Normalize m (i.e. make its most significant bit set) as required by division functions below. */ count_leading_zeros (m_zero_cnt, mp[mn - 1]); m_zero_cnt -= GMP_NAIL_BITS; if (m_zero_cnt != 0) { mp_ptr new_mp = TMP_ALLOC_LIMBS (mn); mpn_lshift (new_mp, mp, mn, m_zero_cnt); mp = new_mp; } bn = ABSIZ(b); bp = PTR(b); if (bn > mn) { /* Reduce possibly huge base. Use a function call to reduce, since we don't want the quotient allocation to live until function return. */ mp_ptr new_bp = TMP_ALLOC_LIMBS (mn); reduce (new_bp, bp, bn, mp, mn); bp = new_bp; bn = mn; /* Canonicalize the base, since we are potentially going to multiply with it quite a few times. */ MPN_NORMALIZE (bp, bn); } if (bn == 0) { SIZ(r) = 0; TMP_FREE; return; } tp = TMP_ALLOC_LIMBS (2 * mn + 1); xp = TMP_ALLOC_LIMBS (mn); qp = TMP_ALLOC_LIMBS (mn + 1); MPN_COPY (xp, bp, bn); xn = bn; e = el; count_leading_zeros (c, e); e = (e << c) << 1; /* shift the exp bits to the left, lose msb */ c = BITS_PER_MP_LIMB - 1 - c; /* Main loop. */ /* If m is already normalized (high bit of high limb set), and b is the same size, but a bigger value, and e==1, then there's no modular reductions done and we can end up with a result out of range at the end. */ if (c == 0) { if (xn == mn && mpn_cmp (xp, mp, mn) >= 0) mpn_sub_n (xp, xp, mp, mn); goto finishup; } while (c != 0) { mpn_sqr_n (tp, xp, xn); tn = 2 * xn; tn -= tp[tn - 1] == 0; if (tn < mn) { MPN_COPY (xp, tp, tn); xn = tn; } else { mpn_tdiv_qr (qp, xp, 0L, tp, tn, mp, mn); xn = mn; } if ((mp_limb_signed_t) e < 0) { mpn_mul (tp, xp, xn, bp, bn); tn = xn + bn; tn -= tp[tn - 1] == 0; if (tn < mn) { MPN_COPY (xp, tp, tn); xn = tn; } else { mpn_tdiv_qr (qp, xp, 0L, tp, tn, mp, mn); xn = mn; } } e <<= 1; c--; } finishup: /* We shifted m left m_zero_cnt steps. Adjust the result by reducing it with the original MOD. */ if (m_zero_cnt != 0) { mp_limb_t cy; cy = mpn_lshift (tp, xp, xn, m_zero_cnt); tp[xn] = cy; xn += cy != 0; if (xn < mn) { MPN_COPY (xp, tp, xn); } else { mpn_tdiv_qr (qp, xp, 0L, tp, xn, mp, mn); xn = mn; } mpn_rshift (xp, xp, xn, m_zero_cnt); } MPN_NORMALIZE (xp, xn); if ((el & 1) != 0 && SIZ(b) < 0 && xn != 0) { mp = PTR(m); /* want original, unnormalized m */ mpn_sub (xp, mp, mn, xp, xn); xn = mn; MPN_NORMALIZE (xp, xn); } MPZ_REALLOC (r, xn); SIZ (r) = xn; MPN_COPY (PTR(r), xp, xn); TMP_FREE; }
void _gst_mpz_tdiv_qr (gst_mpz *quot, gst_mpz *rem, const gst_mpz *num, const gst_mpz *den) { mp_ptr np, dp; mp_ptr qp, rp; mp_size_t nsize = num->size; mp_size_t dsize = den->size; mp_size_t qsize; mp_size_t sign_remainder = nsize; mp_size_t sign_quotient = nsize ^ dsize; nsize = ABS (nsize); dsize = ABS (dsize); /* Ensure space is enough for quotient and remainder. */ qsize = nsize - dsize + 1; /* qsize cannot be bigger than this. */ if (qsize <= 0) { if (num != rem) { gst_mpz_realloc (rem, nsize); rem->size = num->size; MPN_COPY (rem->d, num->d, nsize); } quot->size = 0; return; } if (quot->alloc < qsize) gst_mpz_realloc (quot, qsize); if (rem->alloc < dsize) gst_mpz_realloc (rem, dsize); qp = quot->d; np = num->d; dp = den->d; rp = rem->d; /* Copy denominator to temporary space if it overlaps with the quotient or remainder. */ if (dp == rp || dp == qp) { mp_ptr tp; tp = (mp_ptr) alloca (dsize * SIZEOF_MP_LIMB_T); MPN_COPY (tp, dp, dsize); dp = tp; } /* Copy numerator to temporary space if it overlaps with the quotient or remainder. */ if (np == rp || np == qp) { mp_ptr tp; tp = (mp_ptr) alloca (nsize * SIZEOF_MP_LIMB_T); MPN_COPY (tp, np, nsize); np = tp; } mpn_tdiv_qr (qp, rp, 0L, np, nsize, dp, dsize); qsize -= qp[qsize - 1] == 0; quot->size = sign_quotient >= 0 ? qsize : -qsize; rem->size = sign_remainder >= 0 ? dsize : -dsize; alloca (0); }
/* mpz_tdiv_qr(quot,rem,dividend,divisor) -- Set QUOT to DIVIDEND/DIVISOR, and REM to DIVIDEND mod DIVISOR. Copyright 1991, 1993, 1994, 2000, 2001, 2005 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "gmp.h" #include "gmp-impl.h" #include "longlong.h" #ifdef BERKELEY_MP #include "mp.h" #endif void #ifndef BERKELEY_MP mpz_tdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr num, mpz_srcptr den) #else /* BERKELEY_MP */ mdiv (mpz_srcptr num, mpz_srcptr den, mpz_ptr quot, mpz_ptr rem) #endif /* BERKELEY_MP */ { mp_size_t ql; mp_size_t ns, ds, nl, dl; mp_ptr np, dp, qp, rp; TMP_DECL; ns = SIZ (num); ds = SIZ (den); nl = ABS (ns); dl = ABS (ds); ql = nl - dl + 1; if (dl == 0) DIVIDE_BY_ZERO; MPZ_REALLOC (rem, dl); if (ql <= 0) { if (num != rem) { mp_ptr np, rp; np = PTR (num); rp = PTR (rem); MPN_COPY (rp, np, nl); SIZ (rem) = SIZ (num); } /* This needs to follow the assignment to rem, in case the numerator and quotient are the same. */ SIZ (quot) = 0; return; } MPZ_REALLOC (quot, ql); TMP_MARK; qp = PTR (quot); rp = PTR (rem); np = PTR (num); dp = PTR (den); /* FIXME: We should think about how to handle the temporary allocation. Perhaps mpn_tdiv_qr should handle it, since it anyway often needs to allocate temp space. */ /* Copy denominator to temporary space if it overlaps with the quotient or remainder. */ if (dp == rp || dp == qp) { mp_ptr tp; tp = (mp_ptr) TMP_ALLOC (dl * BYTES_PER_MP_LIMB); MPN_COPY (tp, dp, dl); dp = tp; } /* Copy numerator to temporary space if it overlaps with the quotient or remainder. */ if (np == rp || np == qp) { mp_ptr tp; tp = (mp_ptr) TMP_ALLOC (nl * BYTES_PER_MP_LIMB); MPN_COPY (tp, np, nl); np = tp; } mpn_tdiv_qr (qp, rp, 0L, np, nl, dp, dl); ql -= qp[ql - 1] == 0; MPN_NORMALIZE (rp, dl); SIZ (quot) = (ns ^ ds) >= 0 ? ql : -ql; SIZ (rem) = ns >= 0 ? dl : -dl; TMP_FREE; }
int mpfr_div (mpfr_ptr q, mpfr_srcptr u, mpfr_srcptr v, mp_rnd_t rnd_mode) { mp_srcptr up, vp, bp; mp_size_t usize, vsize; mp_ptr ap, qp, rp; mp_size_t asize, bsize, qsize, rsize; mp_exp_t qexp; mp_size_t err, k; mp_limb_t tonearest; int inex, sh, can_round = 0, sign_quotient; unsigned int cc = 0, rw; TMP_DECL (marker); /************************************************************************** * * * This part of the code deals with special cases * * * **************************************************************************/ if (MPFR_ARE_SINGULAR(u,v)) { if (MPFR_IS_NAN(u) || MPFR_IS_NAN(v)) { MPFR_SET_NAN(q); MPFR_RET_NAN; } sign_quotient = MPFR_MULT_SIGN( MPFR_SIGN(u) , MPFR_SIGN(v) ); MPFR_SET_SIGN(q, sign_quotient); if (MPFR_IS_INF(u)) { if (MPFR_IS_INF(v)) { MPFR_SET_NAN(q); MPFR_RET_NAN; } else { MPFR_SET_INF(q); MPFR_RET(0); } } else if (MPFR_IS_INF(v)) { MPFR_SET_ZERO(q); MPFR_RET(0); } else if (MPFR_IS_ZERO(v)) { if (MPFR_IS_ZERO(u)) { MPFR_SET_NAN(q); MPFR_RET_NAN; } else { MPFR_SET_INF(q); MPFR_RET(0); } } else { MPFR_ASSERTD(MPFR_IS_ZERO(u)); MPFR_SET_ZERO(q); MPFR_RET(0); } } MPFR_CLEAR_FLAGS(q); /************************************************************************** * * * End of the part concerning special values. * * * **************************************************************************/ sign_quotient = MPFR_MULT_SIGN( MPFR_SIGN(u) , MPFR_SIGN(v) ); up = MPFR_MANT(u); vp = MPFR_MANT(v); MPFR_SET_SIGN(q, sign_quotient); TMP_MARK (marker); usize = MPFR_LIMB_SIZE(u); vsize = MPFR_LIMB_SIZE(v); /************************************************************************** * * * First try to use only part of u, v. If this is not sufficient, * * use the full u and v, to avoid long computations eg. in the case * * u = v. * * * **************************************************************************/ /* The dividend is a, length asize. The divisor is b, length bsize. */ qsize = (MPFR_PREC(q) + 3) / BITS_PER_MP_LIMB + 1; /* in case PREC(q)=PREC(v), then vsize=qsize with probability 1-4/b where b is the number of bits per limb */ if (MPFR_LIKELY(vsize <= qsize)) { bsize = vsize; bp = vp; } else /* qsize < vsize: take only the qsize high limbs of the divisor */ { bsize = qsize; bp = (mp_srcptr) vp + (vsize - qsize); } /* we have {bp, bsize} * (1 + errb) = (true divisor) with 0 <= errb < 2^(-qsize*BITS_PER_MP_LIMB+1) */ asize = bsize + qsize; ap = (mp_ptr) TMP_ALLOC (asize * BYTES_PER_MP_LIMB); /* if all arguments have same precision, then asize will be about 2*usize */ if (MPFR_LIKELY(asize > usize)) { /* copy u into the high limbs of {ap, asize}, and pad with zeroes */ /* FIXME: could we copy only the qsize high limbs of the dividend? */ MPN_COPY (ap + asize - usize, up, usize); MPN_ZERO (ap, asize - usize); } else /* truncate the high asize limbs of u into {ap, asize} */ MPN_COPY (ap, up + usize - asize, asize); /* we have {ap, asize} = (true dividend) * (1 - erra) with 0 <= erra < 2^(-asize*BITS_PER_MP_LIMB). This {ap, asize} / {bp, bsize} = (true dividend) / (true divisor) * (1 - erra) (1 + errb) */ /* Allocate limbs for quotient and remainder. */ qp = (mp_ptr) TMP_ALLOC ((qsize + 1) * BYTES_PER_MP_LIMB); rp = (mp_ptr) TMP_ALLOC (bsize * BYTES_PER_MP_LIMB); rsize = bsize; mpn_tdiv_qr (qp, rp, 0, ap, asize, bp, bsize); sh = - (int) qp[qsize]; /* since u and v are normalized, sh is 0 or -1 */ /* we have {qp, qsize + 1} = {ap, asize} / {bp, bsize} (1 - errq) with 0 <= errq < 2^(-qsize*BITS_PER_MP_LIMB+1+sh) thus {qp, qsize + 1} = (true dividend) / (true divisor) * (1 - erra) (1 + errb) (1 - errq). In fact, since the truncated dividend and {rp, bsize} do not overlap, we have: {qp, qsize + 1} = (true dividend) / (true divisor) * (1 - erra') (1 + errb) where 0 <= erra' < 2^(-qsize*BITS_PER_MP_LIMB+sh) */ /* Estimate number of correct bits. */ err = qsize * BITS_PER_MP_LIMB; /* We want to check if rounding is possible, but without normalizing because we might have to divide again if rounding is impossible, or if the result might be exact. We have however to mimic normalization */ /* To detect asap if the result is inexact, so as to avoid doing the division completely, we perform the following check : - if rnd_mode != GMP_RNDN, and the result is exact, we are unable to round simultaneously to zero and to infinity ; - if rnd_mode == GMP_RNDN, and if we can round to zero with one extra bit of precision, we can decide rounding. Hence in that case, check as in the case of GMP_RNDN, with one extra bit. Note that in the case of close to even rounding we shall do the division completely, but this is necessary anyway : we need to know whether this is really even rounding or not. */ if (MPFR_UNLIKELY(asize < usize || bsize < vsize)) { { mp_rnd_t rnd_mode1, rnd_mode2; mp_exp_t tmp_exp; mp_prec_t tmp_prec; if (bsize < vsize) err -= 2; /* divisor is truncated */ #if 0 /* commented this out since the truncation of the dividend is already taken into account in {rp, bsize}, which does not overlap with the neglected part of the dividend */ else if (asize < usize) err --; /* dividend is truncated */ #endif if (MPFR_LIKELY(rnd_mode == GMP_RNDN)) { rnd_mode1 = GMP_RNDZ; rnd_mode2 = MPFR_IS_POS_SIGN(sign_quotient) ? GMP_RNDU : GMP_RNDD; sh++; } else { rnd_mode1 = rnd_mode; switch (rnd_mode) { case GMP_RNDU: rnd_mode2 = GMP_RNDD; break; case GMP_RNDD: rnd_mode2 = GMP_RNDU; break; default: rnd_mode2 = MPFR_IS_POS_SIGN(sign_quotient) ? GMP_RNDU : GMP_RNDD; break; } } tmp_exp = err + sh + BITS_PER_MP_LIMB; tmp_prec = MPFR_PREC(q) + sh + BITS_PER_MP_LIMB; can_round = mpfr_can_round_raw (qp, qsize + 1, sign_quotient, tmp_exp, GMP_RNDN, rnd_mode1, tmp_prec) & mpfr_can_round_raw (qp, qsize + 1, sign_quotient, tmp_exp, GMP_RNDN, rnd_mode2, tmp_prec); /* restore original value of sh, i.e. sh = - qp[qsize] */ sh -= (rnd_mode == GMP_RNDN); }
/* Perform a few steps, using some of mpn_nhgcd2, subtraction and division. Reduces the size by almost one limb or more, but never below the given size s. Return new size for a and b, or 0 if no more steps are possible. M = NULL is allowed, if M is not needed. Needs temporary space for division, n + 1 limbs, and for ngcd_matrix1_vector, n limbs. */ mp_size_t mpn_ngcd_step (mp_size_t n, mp_ptr ap, mp_ptr bp, mp_size_t s, struct ngcd_matrix *M, mp_ptr tp) { struct ngcd_matrix1 M1; mp_limb_t mask; mp_limb_t ah, al, bh, bl; mp_size_t an, bn, qn; mp_ptr qp; mp_ptr rp; int col; ASSERT (n > s); mask = ap[n-1] | bp[n-1]; ASSERT (mask > 0); if (n == s + 1) { if (mask < 4) goto subtract; ah = ap[n-1]; al = ap[n-2]; bh = bp[n-1]; bl = bp[n-2]; } else if (mask & GMP_NUMB_HIGHBIT) { ah = ap[n-1]; al = ap[n-2]; bh = bp[n-1]; bl = bp[n-2]; } else { int shift; count_leading_zeros (shift, mask); ah = MPN_EXTRACT_LIMB (shift, ap[n-1], ap[n-2]); al = MPN_EXTRACT_LIMB (shift, ap[n-2], ap[n-3]); bh = MPN_EXTRACT_LIMB (shift, bp[n-1], bp[n-2]); bl = MPN_EXTRACT_LIMB (shift, bp[n-2], bp[n-3]); } /* Try an mpn_nhgcd2 step */ if (mpn_nhgcd2 (ah, al, bh, bl, &M1)) { /* Multiply M <- M * M1 */ if (M) ngcd_matrix_mul_1 (M, &M1); /* Multiply M1^{-1} (a;b) */ return mpn_ngcd_matrix1_vector (&M1, n, ap, bp, tp); } subtract: /* There are two ways in which mpn_nhgcd2 can fail. Either one of ah and bh was too small, or ah, bh were (almost) equal. Perform one subtraction step (for possible cancellation of high limbs), followed by one division. */ /* Since we must ensure that #(a-b) > s, we handle cancellation of high limbs explicitly up front. (FIXME: Or is it better to just subtract, normalize, and use an addition to undo if it turns out the the difference is too small?) */ for (an = n; an > s; an--) if (ap[an-1] != bp[an-1]) break; if (an == s) return 0; /* Maintain a > b. When needed, swap a and b, and let col keep track of how to update M. */ if (ap[an-1] > bp[an-1]) { /* a is largest. In the subtraction step, we need to update column 1 of M */ col = 1; } else { MP_PTR_SWAP (ap, bp); col = 0; } bn = n; MPN_NORMALIZE (bp, bn); if (bn <= s) return 0; /* We have #a, #b > s. When is it possible that #(a-b) < s? For cancellation to happen, the numbers must be of the form a = x + 1, 0, ..., 0, al b = x , GMP_NUMB_MAX, ..., GMP_NUMB_MAX, bl where al, bl denotes the least significant k limbs. If al < bl, then #(a-b) < k, and if also high(al) != 0, high(bl) != GMP_NUMB_MAX, then #(a-b) = k. If al >= bl, then #(a-b) = k + 1. */ if (ap[an-1] == bp[an-1] + 1) { mp_size_t k; int c; for (k = an-1; k > s; k--) if (ap[k-1] != 0 || bp[k-1] != GMP_NUMB_MAX) break; MPN_CMP (c, ap, bp, k); if (c < 0) { mp_limb_t cy; /* The limbs from k and up are cancelled. */ if (k == s) return 0; cy = mpn_sub_n (ap, ap, bp, k); ASSERT (cy == 1); an = k; } else { ASSERT_NOCARRY (mpn_sub_n (ap, ap, bp, k)); ap[k] = 1; an = k + 1; } } else ASSERT_NOCARRY (mpn_sub_n (ap, ap, bp, an)); ASSERT (an > s); ASSERT (ap[an-1] > 0); ASSERT (bn > s); ASSERT (bp[bn-1] > 0); if (M) ngcd_matrix_update_1 (M, col); if (an < bn) { MPN_PTR_SWAP (ap, an, bp, bn); col ^= 1; } else if (an == bn) { int c; MPN_CMP (c, ap, bp, an); if (c < 0) { MP_PTR_SWAP (ap, bp); col ^= 1; } } /* Divide a / b. Store first the quotient (qn limbs) and then the remainder (bn limbs) starting at tp. */ qn = an + 1 - bn; qp = tp; rp = tp + qn; /* FIXME: We could use an approximate division, that may return a too small quotient, and only guarantess that the size of r is almost the size of b. */ mpn_tdiv_qr (qp, rp, 0, ap, an, bp, bn); qn -= (qp[qn -1] == 0); /* Normalize remainder */ an = bn; for ( ; an > s; an--) if (rp[an-1] > 0) break; if (an > s) /* Include leading zero limbs */ MPN_COPY (ap, rp, bn); else { /* Quotient is too large */ mp_limb_t cy; cy = mpn_add (ap, bp, bn, rp, an); if (cy > 0) { ASSERT (bn < n); ap[bn] = cy; bp[bn] = 0; bn++; } MPN_DECR_U (qp, qn, 1); qn -= (qp[qn-1] == 0); } if (qn > 0 && M) ngcd_matrix_update_q (M, qp, qn, col); return bn; }
mp_size_t mpn_gcdext (mp_ptr gp, mp_ptr up, mp_size_t *usizep, mp_ptr ap, mp_size_t an, mp_ptr bp, mp_size_t n) { mp_size_t talloc; mp_size_t scratch; mp_size_t matrix_scratch; mp_size_t ualloc = n + 1; mp_size_t un; mp_ptr u0; mp_ptr u1; mp_ptr tp; TMP_DECL; ASSERT (an >= n); ASSERT (n > 0); TMP_MARK; /* FIXME: Check for small sizes first, before setting up temporary storage etc. */ talloc = MPN_GCDEXT_LEHMER_N_ITCH(n); /* For initial division */ scratch = an - n + 1; if (scratch > talloc) talloc = scratch; if (ABOVE_THRESHOLD (n, GCDEXT_DC_THRESHOLD)) { /* For hgcd loop. */ mp_size_t hgcd_scratch; mp_size_t update_scratch; mp_size_t p1 = CHOOSE_P_1 (n); mp_size_t p2 = CHOOSE_P_2 (n); mp_size_t min_p = MIN(p1, p2); mp_size_t max_p = MAX(p1, p2); matrix_scratch = MPN_HGCD_MATRIX_INIT_ITCH (n - min_p); hgcd_scratch = mpn_hgcd_itch (n - min_p); update_scratch = max_p + n - 1; scratch = matrix_scratch + MAX(hgcd_scratch, update_scratch); if (scratch > talloc) talloc = scratch; /* Final mpn_gcdext_lehmer_n call. Need space for u and for copies of a and b. */ scratch = MPN_GCDEXT_LEHMER_N_ITCH (GCDEXT_DC_THRESHOLD) + 3*GCDEXT_DC_THRESHOLD; if (scratch > talloc) talloc = scratch; /* Cofactors u0 and u1 */ talloc += 2*(n+1); } tp = TMP_ALLOC_LIMBS(talloc); if (an > n) { mpn_tdiv_qr (tp, ap, 0, ap, an, bp, n); if (mpn_zero_p (ap, n)) { MPN_COPY (gp, bp, n); *usizep = 0; TMP_FREE; return n; } } if (BELOW_THRESHOLD (n, GCDEXT_DC_THRESHOLD)) { mp_size_t gn = mpn_gcdext_lehmer_n(gp, up, usizep, ap, bp, n, tp); TMP_FREE; return gn; } MPN_ZERO (tp, 2*ualloc); u0 = tp; tp += ualloc; u1 = tp; tp += ualloc; { /* For the first hgcd call, there are no u updates, and it makes some sense to use a different choice for p. */ /* FIXME: We could trim use of temporary storage, since u0 and u1 are not used yet. For the hgcd call, we could swap in the u0 and u1 pointers for the relevant matrix elements. */ struct hgcd_matrix M; mp_size_t p = CHOOSE_P_1 (n); mp_size_t nn; mpn_hgcd_matrix_init (&M, n - p, tp); nn = mpn_hgcd (ap + p, bp + p, n - p, &M, tp + matrix_scratch); if (nn > 0) { ASSERT (M.n <= (n - p - 1)/2); ASSERT (M.n + p <= (p + n - 1) / 2); /* Temporary storage 2 (p + M->n) <= p + n - 1 */ n = mpn_hgcd_matrix_adjust (&M, p + nn, ap, bp, p, tp + matrix_scratch); MPN_COPY (u0, M.p[1][0], M.n); MPN_COPY (u1, M.p[1][1], M.n); un = M.n; while ( (u0[un-1] | u1[un-1] ) == 0) un--; } else { /* mpn_hgcd has failed. Then either one of a or b is very small, or the difference is very small. Perform one subtraction followed by one division. */ mp_size_t gn; mp_size_t updated_un = 1; u1[0] = 1; /* Temporary storage 2n + 1 */ n = mpn_gcdext_subdiv_step (gp, &gn, up, usizep, ap, bp, n, u0, u1, &updated_un, tp, tp + n); if (n == 0) { TMP_FREE; return gn; } un = updated_un; ASSERT (un < ualloc); } } while (ABOVE_THRESHOLD (n, GCDEXT_DC_THRESHOLD)) { struct hgcd_matrix M; mp_size_t p = CHOOSE_P_2 (n); mp_size_t nn; mpn_hgcd_matrix_init (&M, n - p, tp); nn = mpn_hgcd (ap + p, bp + p, n - p, &M, tp + matrix_scratch); if (nn > 0) { mp_ptr t0; t0 = tp + matrix_scratch; ASSERT (M.n <= (n - p - 1)/2); ASSERT (M.n + p <= (p + n - 1) / 2); /* Temporary storage 2 (p + M->n) <= p + n - 1 */ n = mpn_hgcd_matrix_adjust (&M, p + nn, ap, bp, p, t0); /* By the same analysis as for mpn_hgcd_matrix_mul */ ASSERT (M.n + un <= ualloc); /* FIXME: This copying could be avoided by some swapping of * pointers. May need more temporary storage, though. */ MPN_COPY (t0, u0, un); /* Temporary storage ualloc */ un = hgcd_mul_matrix_vector (&M, u0, t0, u1, un, t0 + un); ASSERT (un < ualloc); ASSERT ( (u0[un-1] | u1[un-1]) > 0); } else { /* mpn_hgcd has failed. Then either one of a or b is very small, or the difference is very small. Perform one subtraction followed by one division. */ mp_size_t gn; mp_size_t updated_un = un; /* Temporary storage 2n + 1 */ n = mpn_gcdext_subdiv_step (gp, &gn, up, usizep, ap, bp, n, u0, u1, &updated_un, tp, tp + n); if (n == 0) { TMP_FREE; return gn; } un = updated_un; ASSERT (un < ualloc); } } if (UNLIKELY (mpn_cmp (ap, bp, n) == 0)) { /* Must return the smallest cofactor, +u1 or -u0 */ int c; MPN_COPY (gp, ap, n); MPN_CMP (c, u0, u1, un); ASSERT (c != 0); if (c < 0) { MPN_NORMALIZE (u0, un); MPN_COPY (up, u0, un); *usizep = -un; } else { MPN_NORMALIZE_NOT_ZERO (u1, un); MPN_COPY (up, u1, un); *usizep = un; } TMP_FREE; return n; } else if (mpn_zero_p (u0, un)) { mp_size_t gn; ASSERT (un == 1); ASSERT (u1[0] == 1); /* g = u a + v b = (u u1 - v u0) A + (...) B = u A + (...) B */ gn = mpn_gcdext_lehmer_n (gp, up, usizep, ap, bp, n, tp); TMP_FREE; return gn; } else { /* We have A = ... a + ... b B = u0 a + u1 b a = u1 A + ... B b = -u0 A + ... B with bounds |u0|, |u1| <= B / min(a, b) Compute g = u a + v b = (u u1 - v u0) A + (...) B Here, u, v are bounded by |u| <= b, |v| <= a */ mp_size_t u0n; mp_size_t u1n; mp_size_t lehmer_un; mp_size_t lehmer_vn; mp_size_t gn; mp_ptr lehmer_up; mp_ptr lehmer_vp; int negate; lehmer_up = tp; tp += n; /* Call mpn_gcdext_lehmer_n with copies of a and b. */ MPN_COPY (tp, ap, n); MPN_COPY (tp + n, bp, n); gn = mpn_gcdext_lehmer_n (gp, lehmer_up, &lehmer_un, tp, tp + n, n, tp + 2*n); u0n = un; MPN_NORMALIZE (u0, u0n); if (lehmer_un == 0) { /* u == 0 ==> v = g / b == 1 ==> g = - u0 A + (...) B */ MPN_COPY (up, u0, u0n); *usizep = -u0n; TMP_FREE; return gn; } lehmer_vp = tp; /* Compute v = (g - u a) / b */ lehmer_vn = compute_v (lehmer_vp, ap, bp, n, gp, gn, lehmer_up, lehmer_un, tp + n + 1); if (lehmer_un > 0) negate = 0; else { lehmer_un = -lehmer_un; negate = 1; } u1n = un; MPN_NORMALIZE (u1, u1n); /* It's possible that u0 = 1, u1 = 0 */ if (u1n == 0) { ASSERT (un == 1); ASSERT (u0[0] == 1); /* u1 == 0 ==> u u1 + v u0 = v */ MPN_COPY (up, lehmer_vp, lehmer_vn); *usizep = negate ? lehmer_vn : - lehmer_vn; TMP_FREE; return gn; } ASSERT (lehmer_un + u1n <= ualloc); ASSERT (lehmer_vn + u0n <= ualloc); /* Now u0, u1, u are non-zero. We may still have v == 0 */ /* Compute u u0 */ if (lehmer_un <= u1n) /* Should be the common case */ mpn_mul (up, u1, u1n, lehmer_up, lehmer_un); else mpn_mul (up, lehmer_up, lehmer_un, u1, u1n); un = u1n + lehmer_un; un -= (up[un - 1] == 0); if (lehmer_vn > 0) { mp_limb_t cy; /* Overwrites old u1 value */ if (lehmer_vn <= u0n) /* Should be the common case */ mpn_mul (u1, u0, u0n, lehmer_vp, lehmer_vn); else mpn_mul (u1, lehmer_vp, lehmer_vn, u0, u0n); u1n = u0n + lehmer_vn; u1n -= (u1[u1n - 1] == 0); if (u1n <= un) { cy = mpn_add (up, up, un, u1, u1n); } else { cy = mpn_add (up, u1, u1n, up, un); un = u1n; } up[un] = cy; un += (cy != 0); ASSERT (un < ualloc); } *usizep = negate ? -un : un; TMP_FREE; return gn; } }
void fmpz_mod(fmpz_t res, const fmpz_t a, const fmpz_t b) { long a0 = a[0]; long b0 = b[0]; unsigned long sizea = FLINT_ABS(a0); unsigned long sizeb = b0; while ((!a[sizea]) && (sizea)) sizea--; while ((!b[sizeb]) && (sizeb)) sizeb--; mp_limb_t mslimb; fmpz_t temp, temp2; if (sizeb == 0) { printf("Error: division by zero!\n"); abort(); } else if (sizea < sizeb) { if ((long) a0 < 0L) { temp = (fmpz_t) flint_stack_alloc(sizeb + 2); fmpz_add(temp, a, b); fmpz_set(res, temp); flint_stack_release(); } else fmpz_set(res, a); return; } else if ((sizea == sizeb) && (fmpz_cmpabs(a, b) < 0L)) { if (fmpz_sgn(a) < 0) fmpz_add(res, a, b); else fmpz_set(res, a); return; } else { if (fmpz_is_one(b)) { fmpz_set_ui(res, 0L); return; } temp = (fmpz_t) flint_stack_alloc(sizea - sizeb + 1); temp2 = (fmpz_t) flint_stack_alloc(sizeb + 2); mpn_tdiv_qr(temp, temp2+1, 0, a+1, sizea, b+1, sizeb); temp2[0] = sizeb; NORM(temp2); if (a0 < 0L) { unsigned long i = 0; for (; i < sizeb; i++) { if (temp2[i+1]) break; } if (i < sizeb) { fmpz_sub(temp2, b, temp2); } fmpz_set(res, temp2); } else fmpz_set(res, temp2); flint_stack_release(); flint_stack_release(); } }
void bn_divn_low(dig_t *c, dig_t *d, dig_t *a, int sa, dig_t *b, int sb) { mpn_tdiv_qr(c, d, 0, a, sa, b, sb); }
int fmpz_divides(fmpz_t q, const fmpz_t a, const fmpz_t b) { long a0 = a[0]; long b0 = b[0]; unsigned long sizea = FLINT_ABS(a0); unsigned long sizeb = FLINT_ABS(b0); mp_limb_t mslimb; fmpz_t temp; if (sizeb == 0) { printf("Error: division by zero!\n"); abort(); } else if (sizea == 0) { q[0] = 0; return 1; } else if (sizea < sizeb) { return 0; } else if (sizea == sizeb) { int cmp = fmpz_cmpabs(a, b); if (cmp < 0) return 0; if (cmp == 0) { if ((long) (a0 ^ b0) < 0L) q[0] = -1L; else q[0] = 1L; q[1] = 1; return 1; } } if (fmpz_is_one(b)) { fmpz_set(q, a); return 1; } if (fmpz_is_m1(b)) { fmpz_neg(q, a); return 1; } temp = (fmpz_t) flint_stack_alloc(sizeb + 2); mpn_tdiv_qr(q+1, temp+1, 0, a+1, sizea, b+1, sizeb); temp[0] = sizeb; NORM(temp); if (temp[0] != 0) { flint_stack_release(); return 0; } q[0] = sizea - sizeb + 1; NORM(q); if ((long) (a0 ^ b0) < 0L) q[0] = -q[0]; flint_stack_release(); return 1; }