void mpz_lcm (mpz_ptr r, mpz_srcptr u, mpz_srcptr v) { mpz_t g; mp_size_t usize, vsize; TMP_DECL; usize = SIZ (u); vsize = SIZ (v); if (usize == 0 || vsize == 0) { SIZ (r) = 0; return; } usize = ABS (usize); vsize = ABS (vsize); if (vsize == 1 || usize == 1) { mp_limb_t vl, gl, c; mp_srcptr up; mp_ptr rp; if (usize == 1) { usize = vsize; MPZ_SRCPTR_SWAP (u, v); } MPZ_REALLOC (r, usize+1); up = PTR(u); vl = PTR(v)[0]; gl = mpn_gcd_1 (up, usize, vl); vl /= gl; rp = PTR(r); c = mpn_mul_1 (rp, up, usize, vl); rp[usize] = c; usize += (c != 0); SIZ(r) = usize; return; } TMP_MARK; MPZ_TMP_INIT (g, usize); /* v != 0 implies |gcd(u,v)| <= |u| */ mpz_gcd (g, u, v); mpz_divexact (g, u, g); mpz_mul (r, g, v); SIZ (r) = ABS (SIZ (r)); /* result always positive */ TMP_FREE; }
void check_one (mpz_srcptr a, mpz_srcptr c, mpz_srcptr d, int want) { int got; int swap; for (swap = 0; swap <= 1; swap++) { got = (mpz_congruent_p (a, c, d) != 0); if (want != got) { printf ("mpz_congruent_p wrong\n"); printf (" expected %d got %d\n", want, got); mpz_trace (" a", a); mpz_trace (" c", c); mpz_trace (" d", d); mp_trace_base = -16; mpz_trace (" a", a); mpz_trace (" c", c); mpz_trace (" d", d); abort (); } if (mpz_fits_ulong_p (c) && mpz_fits_ulong_p (d)) { unsigned long uc = mpz_get_ui (c); unsigned long ud = mpz_get_ui (d); got = (mpz_congruent_ui_p (a, uc, ud) != 0); if (want != got) { printf ("mpz_congruent_ui_p wrong\n"); printf (" expected %d got %d\n", want, got); mpz_trace (" a", a); printf (" c=%lu\n", uc); printf (" d=%lu\n", ud); mp_trace_base = -16; mpz_trace (" a", a); printf (" c=0x%lX\n", uc); printf (" d=0x%lX\n", ud); abort (); } } MPZ_SRCPTR_SWAP (a, c); } }
void mpz_mul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v) { mp_size_t usize; mp_size_t vsize; mp_size_t wsize; mp_size_t sign_product; mp_ptr up, vp; mp_ptr wp; mp_ptr free_me; size_t free_me_size; mp_limb_t cy_limb; TMP_DECL; usize = SIZ (u); vsize = SIZ (v); sign_product = usize ^ vsize; usize = ABS (usize); vsize = ABS (vsize); if (usize < vsize) { MPZ_SRCPTR_SWAP (u, v); MP_SIZE_T_SWAP (usize, vsize); } if (vsize == 0) { SIZ (w) = 0; return; } #if HAVE_NATIVE_mpn_mul_2 if (vsize <= 2) { wp = MPZ_REALLOC (w, usize+vsize); if (vsize == 1) cy_limb = mpn_mul_1 (wp, PTR (u), usize, PTR (v)[0]); else { cy_limb = mpn_mul_2 (wp, PTR (u), usize, PTR (v)); usize++; } wp[usize] = cy_limb; usize += (cy_limb != 0); SIZ (w) = (sign_product >= 0 ? usize : -usize); return; } #else if (vsize == 1) { wp = MPZ_REALLOC (w, usize+1); cy_limb = mpn_mul_1 (wp, PTR (u), usize, PTR (v)[0]); wp[usize] = cy_limb; usize += (cy_limb != 0); SIZ (w) = (sign_product >= 0 ? usize : -usize); return; } #endif TMP_MARK; free_me = NULL; up = PTR (u); vp = PTR (v); wp = PTR (w); /* Ensure W has space enough to store the result. */ wsize = usize + vsize; if (ALLOC (w) < wsize) { if (wp == up || wp == vp) { free_me = wp; free_me_size = ALLOC (w); } else (*__gmp_free_func) (wp, (size_t) ALLOC (w) * GMP_LIMB_BYTES); ALLOC (w) = wsize; wp = __GMP_ALLOCATE_FUNC_LIMBS (wsize); PTR (w) = wp; } else { /* Make U and V not overlap with W. */ if (wp == up) { /* W and U are identical. Allocate temporary space for U. */ up = TMP_ALLOC_LIMBS (usize); /* Is V identical too? Keep it identical with U. */ if (wp == vp) vp = up; /* Copy to the temporary space. */ MPN_COPY (up, wp, usize); } else if (wp == vp) { /* W and V are identical. Allocate temporary space for V. */ vp = TMP_ALLOC_LIMBS (vsize); /* Copy to the temporary space. */ MPN_COPY (vp, wp, vsize); } } if (up == vp) { mpn_sqr (wp, up, usize); cy_limb = wp[wsize - 1]; } else { cy_limb = mpn_mul (wp, up, usize, vp, vsize); } wsize -= cy_limb == 0; SIZ (w) = sign_product < 0 ? -wsize : wsize; if (free_me != NULL) (*__gmp_free_func) (free_me, free_me_size * GMP_LIMB_BYTES); TMP_FREE; }
int mpz_congruent_2exp_p (mpz_srcptr a, mpz_srcptr c, mp_bitcnt_t d) { mp_size_t i, dlimbs; unsigned dbits; mp_ptr ap, cp; mp_limb_t dmask, alimb, climb, sum; mp_size_t asize_signed, csize_signed, asize, csize; if (ABSIZ(a) < ABSIZ(c)) MPZ_SRCPTR_SWAP (a, c); dlimbs = d / GMP_NUMB_BITS; dbits = d % GMP_NUMB_BITS; dmask = (CNST_LIMB(1) << dbits) - 1; ap = PTR(a); cp = PTR(c); asize_signed = SIZ(a); asize = ABS(asize_signed); csize_signed = SIZ(c); csize = ABS(csize_signed); if (csize_signed == 0) goto a_zeros; if ((asize_signed ^ csize_signed) >= 0) { /* same signs, direct comparison */ /* a==c for limbs in common */ if (mpn_cmp (ap, cp, MIN (csize, dlimbs)) != 0) return 0; /* if that's all of dlimbs, then a==c for remaining bits */ if (csize > dlimbs) return ((ap[dlimbs]-cp[dlimbs]) & dmask) == 0; a_zeros: /* a remains, need all zero bits */ /* if d covers all of a and c, then must be exactly equal */ if (asize <= dlimbs) return asize == csize; /* whole limbs zero */ for (i = csize; i < dlimbs; i++) if (ap[i] != 0) return 0; /* partial limb zero */ return (ap[dlimbs] & dmask) == 0; } else { /* different signs, negated comparison */ /* common low zero limbs, stopping at first non-zeros, which must match twos complement */ i = 0; for (;;) { ASSERT (i < csize); /* always have a non-zero limb on c */ alimb = ap[i]; climb = cp[i]; sum = (alimb + climb) & GMP_NUMB_MASK; if (i >= dlimbs) return (sum & dmask) == 0; i++; /* require both zero, or first non-zeros as twos-complements */ if (sum != 0) return 0; if (alimb != 0) break; } /* further limbs matching as ones-complement */ for (;;) { if (i >= csize) break; alimb = ap[i]; climb = cp[i]; sum = (alimb + climb + 1) & GMP_NUMB_MASK; if (i >= dlimbs) return (sum & dmask) == 0; if (sum != 0) return 0; i++; } /* no more c, so require all 1 bits in a */ if (asize < dlimbs) return 0; /* not enough a */ /* whole limbs */ for ( ; i < dlimbs; i++) if (ap[i] != GMP_NUMB_MAX) return 0; /* if only whole limbs, no further fetches from a */ if (dbits == 0) return 1; /* need enough a */ if (asize == dlimbs) return 0; return ((ap[dlimbs]+1) & dmask) == 0; } }
void mpz_gcdext (mpz_ptr g, mpz_ptr s, mpz_ptr t, mpz_srcptr a, mpz_srcptr b) { mp_size_t asize, bsize; mp_ptr tmp_ap, tmp_bp; mp_size_t gsize, ssize, tmp_ssize; mp_ptr gp, tmp_gp, tmp_sp; TMP_DECL; /* mpn_gcdext requires that Usize >= Vsize. Therefore, we often have to swap U and V. The computed cofactor will be the "smallest" one, which is faster to produce. The wanted one will be computed here; this is needed anyway when both are requested. */ asize = ABSIZ (a); bsize = ABSIZ (b); if (asize < bsize) { MPZ_SRCPTR_SWAP (a, b); MP_SIZE_T_SWAP (asize, bsize); MPZ_PTR_SWAP (s, t); } if (bsize == 0) { /* g = |a|, s = sgn(a), t = 0. */ ssize = SIZ (a) >= 0 ? (asize != 0) : -1; gp = MPZ_REALLOC (g, asize); MPN_COPY (gp, PTR (a), asize); SIZ (g) = asize; if (t != NULL) SIZ (t) = 0; if (s != NULL) { SIZ (s) = ssize; PTR (s)[0] = 1; } return; } TMP_MARK; TMP_ALLOC_LIMBS_2 (tmp_ap, asize, tmp_bp, bsize); MPN_COPY (tmp_ap, PTR (a), asize); MPN_COPY (tmp_bp, PTR (b), bsize); TMP_ALLOC_LIMBS_2 (tmp_gp, bsize, tmp_sp, bsize + 1); gsize = mpn_gcdext (tmp_gp, tmp_sp, &tmp_ssize, tmp_ap, asize, tmp_bp, bsize); ssize = ABS (tmp_ssize); tmp_ssize = SIZ (a) >= 0 ? tmp_ssize : -tmp_ssize; if (t != NULL) { mpz_t x; __mpz_struct gtmp, stmp; PTR (>mp) = tmp_gp; SIZ (>mp) = gsize; PTR (&stmp) = tmp_sp; SIZ (&stmp) = tmp_ssize; MPZ_TMP_INIT (x, ssize + asize + 1); mpz_mul (x, &stmp, a); mpz_sub (x, >mp, x); mpz_divexact (t, x, b); } if (s != NULL) { mp_ptr sp; sp = MPZ_REALLOC (s, ssize); MPN_COPY (sp, tmp_sp, ssize); SIZ (s) = tmp_ssize; } gp = MPZ_REALLOC (g, gsize); MPN_COPY (gp, tmp_gp, gsize); SIZ (g) = gsize; TMP_FREE; }
REGPARM_ATTR (1) static void mpz_aorsmul (mpz_ptr w, mpz_srcptr x, mpz_srcptr y, mp_size_t sub) { mp_size_t xsize, ysize, tsize, wsize, wsize_signed; mp_ptr wp, tp; mp_limb_t c, high; TMP_DECL; /* w unaffected if x==0 or y==0 */ xsize = SIZ(x); ysize = SIZ(y); if (xsize == 0 || ysize == 0) return; /* make x the bigger of the two */ if (ABS(ysize) > ABS(xsize)) { MPZ_SRCPTR_SWAP (x, y); MP_SIZE_T_SWAP (xsize, ysize); } sub ^= ysize; ysize = ABS(ysize); /* use mpn_addmul_1/mpn_submul_1 if possible */ if (ysize == 1) { mpz_aorsmul_1 (w, x, PTR(y)[0], sub); return; } sub ^= xsize; xsize = ABS(xsize); wsize_signed = SIZ(w); sub ^= wsize_signed; wsize = ABS(wsize_signed); tsize = xsize + ysize; wp = MPZ_REALLOC (w, MAX (wsize, tsize) + 1); if (wsize_signed == 0) { /* Nothing to add to, just set w=x*y. No w==x or w==y overlap here, since we know x,y!=0 but w==0. */ high = mpn_mul (wp, PTR(x),xsize, PTR(y),ysize); tsize -= (high == 0); SIZ(w) = (sub >= 0 ? tsize : -tsize); return; } TMP_MARK; tp = TMP_ALLOC_LIMBS (tsize); high = mpn_mul (tp, PTR(x),xsize, PTR(y),ysize); tsize -= (high == 0); ASSERT (tp[tsize-1] != 0); if (sub >= 0) { mp_srcptr up = wp; mp_size_t usize = wsize; if (usize < tsize) { up = tp; usize = tsize; tp = wp; tsize = wsize; wsize = usize; } c = mpn_add (wp, up,usize, tp,tsize); wp[wsize] = c; wsize += (c != 0); } else { mp_srcptr up = wp; mp_size_t usize = wsize; if (mpn_cmp_twosizes_lt (up,usize, tp,tsize)) { up = tp; usize = tsize; tp = wp; tsize = wsize; wsize = usize; wsize_signed = -wsize_signed; } ASSERT_NOCARRY (mpn_sub (wp, up,usize, tp,tsize)); wsize = usize; MPN_NORMALIZE (wp, wsize); } SIZ(w) = (wsize_signed >= 0 ? wsize : -wsize); TMP_FREE; }
int mpz_congruent_p (mpz_srcptr a, mpz_srcptr c, mpz_srcptr d) { mp_size_t asize, csize, dsize, sign; mp_srcptr ap, cp, dp; mp_ptr xp; mp_limb_t alow, clow, dlow, dmask, r; int result; TMP_DECL; dsize = SIZ(d); if (UNLIKELY (dsize == 0)) return (mpz_cmp (a, c) == 0); dsize = ABS(dsize); dp = PTR(d); if (ABSIZ(a) < ABSIZ(c)) MPZ_SRCPTR_SWAP (a, c); asize = SIZ(a); csize = SIZ(c); sign = (asize ^ csize); asize = ABS(asize); ap = PTR(a); if (csize == 0) return mpn_divisible_p (ap, asize, dp, dsize); csize = ABS(csize); cp = PTR(c); alow = ap[0]; clow = cp[0]; dlow = dp[0]; /* Check a==c mod low zero bits of dlow. This might catch a few cases of a!=c quickly, and it helps the csize==1 special cases below. */ dmask = LOW_ZEROS_MASK (dlow) & GMP_NUMB_MASK; alow = (sign >= 0 ? alow : -alow); if (((alow-clow) & dmask) != 0) return 0; if (csize == 1) { if (dsize == 1) { cong_1: if (sign < 0) NEG_MOD (clow, clow, dlow); if (ABOVE_THRESHOLD (asize, BMOD_1_TO_MOD_1_THRESHOLD)) { r = mpn_mod_1 (ap, asize, dlow); if (clow < dlow) return r == clow; else return r == (clow % dlow); } if ((dlow & 1) == 0) { /* Strip low zero bits to get odd d required by modexact. If d==e*2^n then a==c mod d if and only if both a==c mod e and a==c mod 2^n, the latter having been done above. */ unsigned twos; count_trailing_zeros (twos, dlow); dlow >>= twos; } r = mpn_modexact_1c_odd (ap, asize, dlow, clow); return r == 0 || r == dlow; }
void mpz_xor (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2) { mp_srcptr op1_ptr, op2_ptr; mp_size_t op1_size, op2_size; mp_ptr res_ptr; mp_size_t res_size, res_alloc; TMP_DECL; TMP_MARK; op1_size = SIZ(op1); op2_size = SIZ(op2); op1_ptr = PTR(op1); op2_ptr = PTR(op2); res_ptr = PTR(res); if (op1_size >= 0) { if (op2_size >= 0) { if (op1_size >= op2_size) { if (ALLOC(res) < op1_size) { _mpz_realloc (res, op1_size); /* No overlapping possible: op1_ptr = PTR(op1); */ op2_ptr = PTR(op2); res_ptr = PTR(res); } if (res_ptr != op1_ptr) MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size); if (LIKELY (op2_size != 0)) mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op2_size); res_size = op1_size; } else { if (ALLOC(res) < op2_size) { _mpz_realloc (res, op2_size); op1_ptr = PTR(op1); /* No overlapping possible: op2_ptr = PTR(op2); */ res_ptr = PTR(res); } if (res_ptr != op2_ptr) MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size); if (LIKELY (op1_size != 0)) mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size); res_size = op2_size; } MPN_NORMALIZE (res_ptr, res_size); SIZ(res) = res_size; return; } else /* op2_size < 0 */ { /* Fall through to the code at the end of the function. */ } } else { if (op2_size < 0) { mp_ptr opx, opy; /* Both operands are negative, the result will be positive. (-OP1) ^ (-OP2) = = ~(OP1 - 1) ^ ~(OP2 - 1) = = (OP1 - 1) ^ (OP2 - 1) */ op1_size = -op1_size; op2_size = -op2_size; /* Possible optimization: Decrease mpn_sub precision, as we won't use the entire res of both. */ TMP_ALLOC_LIMBS_2 (opx, op1_size, opy, op2_size); mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1); op1_ptr = opx; mpn_sub_1 (opy, op2_ptr, op2_size, (mp_limb_t) 1); op2_ptr = opy; if (op1_size > op2_size) MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size); res_alloc = op2_size; res_ptr = MPZ_REALLOC (res, res_alloc); MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size); mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size); res_size = op2_size; MPN_NORMALIZE (res_ptr, res_size); SIZ(res) = res_size; TMP_FREE; return; } else { /* We should compute -OP1 ^ OP2. Swap OP1 and OP2 and fall through to the code that handles OP1 ^ -OP2. */ MPZ_SRCPTR_SWAP (op1, op2); MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size); } } { mp_ptr opx; mp_limb_t cy; /* Operand 2 negative, so will be the result. -(OP1 ^ (-OP2)) = -(OP1 ^ ~(OP2 - 1)) = = ~(OP1 ^ ~(OP2 - 1)) + 1 = = (OP1 ^ (OP2 - 1)) + 1 */ op2_size = -op2_size; opx = TMP_ALLOC_LIMBS (op2_size); mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1); op2_ptr = opx; res_alloc = MAX (op1_size, op2_size) + 1; if (ALLOC(res) < res_alloc) { _mpz_realloc (res, res_alloc); op1_ptr = PTR(op1); /* op2_ptr points to temporary space. */ res_ptr = PTR(res); } if (op1_size > op2_size) { MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size); mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op2_size); res_size = op1_size; } else { MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size); if (LIKELY (op1_size != 0)) mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size); res_size = op2_size; } cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1); res_ptr[res_size] = cy; res_size += (cy != 0); MPN_NORMALIZE (res_ptr, res_size); SIZ(res) = -res_size; TMP_FREE; } }
void mpz_ior (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2) { mp_srcptr op1_ptr, op2_ptr; mp_size_t op1_size, op2_size; mp_ptr res_ptr; mp_size_t res_size; mp_size_t i; TMP_DECL; TMP_MARK; op1_size = op1->_mp_size; op2_size = op2->_mp_size; op1_ptr = op1->_mp_d; op2_ptr = op2->_mp_d; res_ptr = res->_mp_d; if (op1_size >= 0) { if (op2_size >= 0) { if (op1_size >= op2_size) { if (res->_mp_alloc < op1_size) { _mpz_realloc (res, op1_size); op1_ptr = op1->_mp_d; op2_ptr = op2->_mp_d; res_ptr = res->_mp_d; } if (res_ptr != op1_ptr) MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size); for (i = op2_size - 1; i >= 0; i--) res_ptr[i] = op1_ptr[i] | op2_ptr[i]; res_size = op1_size; } else { if (res->_mp_alloc < op2_size) { _mpz_realloc (res, op2_size); op1_ptr = op1->_mp_d; op2_ptr = op2->_mp_d; res_ptr = res->_mp_d; } if (res_ptr != op2_ptr) MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size); for (i = op1_size - 1; i >= 0; i--) res_ptr[i] = op1_ptr[i] | op2_ptr[i]; res_size = op2_size; } res->_mp_size = res_size; return; } else /* op2_size < 0 */ { /* Fall through to the code at the end of the function. */ } } else { if (op2_size < 0) { mp_ptr opx; mp_limb_t cy; /* Both operands are negative, so will be the result. -((-OP1) | (-OP2)) = -(~(OP1 - 1) | ~(OP2 - 1)) = = ~(~(OP1 - 1) | ~(OP2 - 1)) + 1 = = ((OP1 - 1) & (OP2 - 1)) + 1 */ op1_size = -op1_size; op2_size = -op2_size; res_size = MIN (op1_size, op2_size); /* Possible optimization: Decrease mpn_sub precision, as we won't use the entire res of both. */ opx = (mp_ptr) TMP_ALLOC (res_size * BYTES_PER_MP_LIMB); mpn_sub_1 (opx, op1_ptr, res_size, (mp_limb_t) 1); op1_ptr = opx; opx = (mp_ptr) TMP_ALLOC (res_size * BYTES_PER_MP_LIMB); mpn_sub_1 (opx, op2_ptr, res_size, (mp_limb_t) 1); op2_ptr = opx; if (res->_mp_alloc < res_size) { _mpz_realloc (res, res_size); res_ptr = res->_mp_d; /* Don't re-read OP1_PTR and OP2_PTR. They point to temporary space--never to the space RES->_mp_d used to point to before reallocation. */ } /* First loop finds the size of the result. */ for (i = res_size - 1; i >= 0; i--) if ((op1_ptr[i] & op2_ptr[i]) != 0) break; res_size = i + 1; if (res_size != 0) { /* Second loop computes the real result. */ for (i = res_size - 1; i >= 0; i--) res_ptr[i] = op1_ptr[i] & op2_ptr[i]; cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1); if (cy) { res_ptr[res_size] = cy; res_size++; } } else { res_ptr[0] = 1; res_size = 1; } res->_mp_size = -res_size; TMP_FREE; return; } else { /* We should compute -OP1 | OP2. Swap OP1 and OP2 and fall through to the code that handles OP1 | -OP2. */ MPZ_SRCPTR_SWAP (op1, op2); MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size); } } { mp_ptr opx; mp_limb_t cy; mp_size_t res_alloc; mp_size_t count; /* Operand 2 negative, so will be the result. -(OP1 | (-OP2)) = -(OP1 | ~(OP2 - 1)) = = ~(OP1 | ~(OP2 - 1)) + 1 = = (~OP1 & (OP2 - 1)) + 1 */ op2_size = -op2_size; res_alloc = op2_size; opx = (mp_ptr) TMP_ALLOC (op2_size * BYTES_PER_MP_LIMB); mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1); op2_ptr = opx; op2_size -= op2_ptr[op2_size - 1] == 0; if (res->_mp_alloc < res_alloc) { _mpz_realloc (res, res_alloc); op1_ptr = op1->_mp_d; res_ptr = res->_mp_d; /* Don't re-read OP2_PTR. It points to temporary space--never to the space RES->_mp_d used to point to before reallocation. */ } if (op1_size >= op2_size) { /* We can just ignore the part of OP1 that stretches above OP2, because the result limbs are zero there. */ /* First loop finds the size of the result. */ for (i = op2_size - 1; i >= 0; i--) if ((~op1_ptr[i] & op2_ptr[i]) != 0) break; res_size = i + 1; count = res_size; } else { res_size = op2_size; /* Copy the part of OP2 that stretches above OP1, to RES. */ MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size); count = op1_size; } if (res_size != 0) { /* Second loop computes the real result. */ for (i = count - 1; i >= 0; i--) res_ptr[i] = ~op1_ptr[i] & op2_ptr[i]; cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1); if (cy) { res_ptr[res_size] = cy; res_size++; } } else { res_ptr[0] = 1; res_size = 1; } res->_mp_size = -res_size; } TMP_FREE; }
void mpz_xor (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2) { mp_srcptr op1_ptr, op2_ptr; mp_size_t op1_size, op2_size; mp_ptr res_ptr; mp_size_t res_size, res_alloc; mp_size_t i; TMP_DECL; TMP_MARK; op1_size = op1->_mp_size; op2_size = op2->_mp_size; op1_ptr = op1->_mp_d; op2_ptr = op2->_mp_d; res_ptr = res->_mp_d; if (op1_size >= 0) { if (op2_size >= 0) { if (op1_size >= op2_size) { if (res->_mp_alloc < op1_size) { _mpz_realloc (res, op1_size); op1_ptr = op1->_mp_d; op2_ptr = op2->_mp_d; res_ptr = res->_mp_d; } if (res_ptr != op1_ptr) MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size); for (i = op2_size - 1; i >= 0; i--) res_ptr[i] = op1_ptr[i] ^ op2_ptr[i]; res_size = op1_size; } else { if (res->_mp_alloc < op2_size) { _mpz_realloc (res, op2_size); op1_ptr = op1->_mp_d; op2_ptr = op2->_mp_d; res_ptr = res->_mp_d; } if (res_ptr != op2_ptr) MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size); for (i = op1_size - 1; i >= 0; i--) res_ptr[i] = op1_ptr[i] ^ op2_ptr[i]; res_size = op2_size; } MPN_NORMALIZE (res_ptr, res_size); res->_mp_size = res_size; return; } else /* op2_size < 0 */ { /* Fall through to the code at the end of the function. */ } } else { if (op2_size < 0) { mp_ptr opx; /* Both operands are negative, the result will be positive. (-OP1) ^ (-OP2) = = ~(OP1 - 1) ^ ~(OP2 - 1) = = (OP1 - 1) ^ (OP2 - 1) */ op1_size = -op1_size; op2_size = -op2_size; /* Possible optimization: Decrease mpn_sub precision, as we won't use the entire res of both. */ opx = (mp_ptr) TMP_ALLOC (op1_size * BYTES_PER_MP_LIMB); mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1); op1_ptr = opx; opx = (mp_ptr) TMP_ALLOC (op2_size * BYTES_PER_MP_LIMB); mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1); op2_ptr = opx; res_alloc = MAX (op1_size, op2_size); if (res->_mp_alloc < res_alloc) { _mpz_realloc (res, res_alloc); res_ptr = res->_mp_d; /* Don't re-read OP1_PTR and OP2_PTR. They point to temporary space--never to the space RES->_mp_d used to point to before reallocation. */ } if (op1_size > op2_size) { MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size); for (i = op2_size - 1; i >= 0; i--) res_ptr[i] = op1_ptr[i] ^ op2_ptr[i]; res_size = op1_size; } else { MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size); for (i = op1_size - 1; i >= 0; i--) res_ptr[i] = op1_ptr[i] ^ op2_ptr[i]; res_size = op2_size; } MPN_NORMALIZE (res_ptr, res_size); res->_mp_size = res_size; TMP_FREE; return; } else { /* We should compute -OP1 ^ OP2. Swap OP1 and OP2 and fall through to the code that handles OP1 ^ -OP2. */ MPZ_SRCPTR_SWAP (op1, op2); MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size); } } { mp_ptr opx; mp_limb_t cy; /* Operand 2 negative, so will be the result. -(OP1 ^ (-OP2)) = -(OP1 ^ ~(OP2 - 1)) = = ~(OP1 ^ ~(OP2 - 1)) + 1 = = (OP1 ^ (OP2 - 1)) + 1 */ op2_size = -op2_size; opx = (mp_ptr) TMP_ALLOC (op2_size * BYTES_PER_MP_LIMB); mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1); op2_ptr = opx; res_alloc = MAX (op1_size, op2_size) + 1; if (res->_mp_alloc < res_alloc) { _mpz_realloc (res, res_alloc); op1_ptr = op1->_mp_d; res_ptr = res->_mp_d; /* Don't re-read OP2_PTR. It points to temporary space--never to the space RES->_mp_d used to point to before reallocation. */ } if (op1_size > op2_size) { MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size); for (i = op2_size - 1; i >= 0; i--) res_ptr[i] = op1_ptr[i] ^ op2_ptr[i]; res_size = op1_size; } else { MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size); for (i = op1_size - 1; i >= 0; i--) res_ptr[i] = op1_ptr[i] ^ op2_ptr[i]; res_size = op2_size; } cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1); if (cy) { res_ptr[res_size] = cy; res_size++; } MPN_NORMALIZE (res_ptr, res_size); res->_mp_size = -res_size; TMP_FREE; } }