2011-12-09 21:50:25 +01:00
|
|
|
|
|
|
|
class Z
|
|
|
|
{
|
|
|
|
public:
|
2011-12-14 19:32:28 +01:00
|
|
|
typedef ::linear_combination<Z> linear_combination;
|
|
|
|
typedef ::linear_combination_const_iter<Z> linear_combination_const_iter;
|
2011-12-09 21:50:25 +01:00
|
|
|
|
2011-12-27 19:40:59 +01:00
|
|
|
private:
|
2011-12-09 21:50:25 +01:00
|
|
|
enum steal { STEAL };
|
|
|
|
|
|
|
|
class Z_impl : public refcounted
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
mpz_t x;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Z_impl () { mpz_init (x); }
|
|
|
|
Z_impl (int init) { mpz_init_set_si (x, init); }
|
|
|
|
Z_impl (copy, mpz_srcptr init) { mpz_init_set (x, init); }
|
|
|
|
Z_impl (steal, mpz_srcptr init) { x[0] = *init; }
|
2011-12-22 21:35:49 +01:00
|
|
|
Z_impl (reader &r)
|
|
|
|
{
|
|
|
|
mpz_init (x);
|
2012-07-27 21:37:47 +02:00
|
|
|
r.read_mpz (x);
|
2011-12-22 21:35:49 +01:00
|
|
|
}
|
|
|
|
|
2011-12-09 21:50:25 +01:00
|
|
|
~Z_impl () { mpz_clear (x); }
|
2011-12-22 21:35:49 +01:00
|
|
|
|
|
|
|
void write_self (writer &w) const
|
|
|
|
{
|
2012-07-27 21:37:47 +02:00
|
|
|
w.write_mpz (x);
|
2011-12-22 21:35:49 +01:00
|
|
|
}
|
2011-12-09 21:50:25 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
ptr<Z_impl> impl;
|
|
|
|
|
|
|
|
Z (steal, mpz_srcptr init) : impl(new Z_impl (STEAL, init)) { }
|
|
|
|
|
|
|
|
public:
|
|
|
|
Z () : impl(new Z_impl) { }
|
|
|
|
Z (int init) : impl(new Z_impl (init)) { }
|
|
|
|
Z (const Z &z) : impl(z.impl) { }
|
|
|
|
Z (copy, const Z &z) : impl(new Z_impl (COPY, z.impl->x)) { }
|
2011-12-22 21:35:49 +01:00
|
|
|
Z (reader &r) : impl(new Z_impl (r)) { }
|
2011-12-09 21:50:25 +01:00
|
|
|
~Z () { }
|
|
|
|
|
|
|
|
Z &operator = (const Z &z) { impl = z.impl; return *this; }
|
|
|
|
Z &operator = (int x) { impl = new Z_impl (x); return *this; }
|
|
|
|
|
|
|
|
bool operator == (const Z &z) const { return mpz_cmp (impl->x, z.impl->x) == 0; }
|
2012-07-27 21:37:47 +02:00
|
|
|
bool operator != (const Z &z) const { return !operator == (z); }
|
2011-12-09 21:50:25 +01:00
|
|
|
|
|
|
|
bool operator == (int y) const { return mpz_cmp_si (impl->x, y) == 0; }
|
|
|
|
bool operator != (int y) const { return !operator == (y); }
|
|
|
|
|
|
|
|
bool operator < (const Z &z) const { return mpz_cmp (impl->x, z.impl->x) < 0; }
|
|
|
|
|
|
|
|
bool is_unit () const
|
|
|
|
{
|
|
|
|
return *this == 1 || *this == -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Z operator + (const Z &z) const
|
|
|
|
{
|
|
|
|
mpz_t x;
|
|
|
|
mpz_init (x);
|
|
|
|
mpz_add (x, impl->x, z.impl->x);
|
|
|
|
return Z (STEAL, x);
|
|
|
|
}
|
|
|
|
|
2011-12-14 19:07:53 +01:00
|
|
|
Z operator - () const
|
|
|
|
{
|
|
|
|
mpz_t x;
|
|
|
|
mpz_init (x);
|
|
|
|
mpz_neg (x, impl->x);
|
|
|
|
return Z (STEAL, x);
|
|
|
|
}
|
|
|
|
|
2011-12-09 21:50:25 +01:00
|
|
|
Z operator - (const Z &z) const
|
|
|
|
{
|
|
|
|
mpz_t x;
|
|
|
|
mpz_init (x);
|
|
|
|
mpz_sub (x, impl->x, z.impl->x);
|
|
|
|
return Z (STEAL, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
Z operator * (const Z &z) const
|
|
|
|
{
|
|
|
|
mpz_t x;
|
|
|
|
mpz_init (x);
|
|
|
|
mpz_mul (x, impl->x, z.impl->x);
|
|
|
|
return Z (STEAL, x);
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:37:47 +02:00
|
|
|
Z operator / (const Z &denom) const
|
2011-12-09 21:50:25 +01:00
|
|
|
{
|
2012-07-27 21:37:47 +02:00
|
|
|
if (mpz_cmp_si (denom.impl->x, 1) == 0)
|
2011-12-09 21:50:25 +01:00
|
|
|
return *this;
|
|
|
|
else
|
|
|
|
{
|
2012-07-27 21:37:47 +02:00
|
|
|
assert (mpz_cmp_si (denom.impl->x, -1) == 0);
|
2011-12-09 21:50:25 +01:00
|
|
|
|
|
|
|
mpz_t x;
|
|
|
|
mpz_init (x);
|
|
|
|
mpz_neg (x, impl->x);
|
|
|
|
return Z (STEAL, x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Z recip () const
|
|
|
|
{
|
|
|
|
assert (is_unit ());
|
|
|
|
return Z (COPY, *this);
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:37:47 +02:00
|
|
|
// *this += z1*z2
|
2011-12-22 21:35:49 +01:00
|
|
|
Z &muladdeq (const Z &z1, const Z &z2)
|
|
|
|
{
|
2011-12-27 19:40:59 +01:00
|
|
|
mpz_addmul (impl->x, z1.impl->x, z2.impl->x);
|
|
|
|
return *this;
|
2011-12-22 21:35:49 +01:00
|
|
|
}
|
|
|
|
|
2011-12-09 21:50:25 +01:00
|
|
|
Z &operator += (const Z &z)
|
|
|
|
{
|
|
|
|
mpz_add (impl->x, impl->x, z.impl->x);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Z &operator -= (const Z &z)
|
|
|
|
{
|
|
|
|
mpz_sub (impl->x, impl->x, z.impl->x);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Z &operator *= (const Z &z)
|
|
|
|
{
|
|
|
|
mpz_mul (impl->x, impl->x, z.impl->x);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Z &operator /= (const Z &z)
|
|
|
|
{
|
|
|
|
if (mpz_cmp_si (z.impl->x, 1) == 0)
|
|
|
|
;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert (mpz_cmp_si (z.impl->x, -1) == 0);
|
|
|
|
mpz_neg (impl->x, impl->x);
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:37:47 +02:00
|
|
|
bool divides (const Z &num) const
|
2011-12-09 21:50:25 +01:00
|
|
|
{
|
2012-07-27 21:37:47 +02:00
|
|
|
return mpz_divisible_p (num.impl->x, impl->x);
|
2011-12-09 21:50:25 +01:00
|
|
|
}
|
2012-07-27 21:37:47 +02:00
|
|
|
bool operator | (const Z &num) const { return divides (num); }
|
2011-12-09 21:50:25 +01:00
|
|
|
|
2012-07-27 21:37:47 +02:00
|
|
|
Z divide_exact (const Z &denom) const
|
2011-12-09 21:50:25 +01:00
|
|
|
{
|
2012-07-27 21:37:47 +02:00
|
|
|
// num = *this
|
2011-12-09 21:50:25 +01:00
|
|
|
mpz_t q;
|
|
|
|
mpz_init (q);
|
2012-07-27 21:37:47 +02:00
|
|
|
mpz_divexact (q, impl->x, denom.impl->x);
|
2011-12-09 21:50:25 +01:00
|
|
|
return Z (STEAL, q);
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:37:47 +02:00
|
|
|
tuple<Z, Z> divide_with_remainder (const Z &denom) const
|
2011-12-09 21:50:25 +01:00
|
|
|
{
|
2012-07-27 21:37:47 +02:00
|
|
|
// *this = num
|
|
|
|
mpz_t q, r;
|
|
|
|
mpz_init (q);
|
|
|
|
mpz_init (r);
|
|
|
|
mpz_tdiv_qr (q, r, impl->x, denom.impl->x);
|
|
|
|
return make_tuple (Z (STEAL, q),
|
|
|
|
Z (STEAL, r));
|
2011-12-09 21:50:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Z gcd (const Z &z) const
|
|
|
|
{
|
|
|
|
mpz_t d;
|
|
|
|
mpz_gcd (d, impl->x, z.impl->x);
|
|
|
|
return Z (STEAL, d);
|
|
|
|
}
|
|
|
|
|
|
|
|
Z lcm (const Z &z) const
|
|
|
|
{
|
|
|
|
mpz_t m;
|
|
|
|
mpz_lcm (m, impl->x, z.impl->x);
|
|
|
|
return Z (STEAL, m);
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:37:47 +02:00
|
|
|
tuple<Z, Z, Z> extended_gcd (const Z &z) const
|
|
|
|
{
|
|
|
|
mpz_t d, s, t;
|
|
|
|
mpz_init (d);
|
|
|
|
mpz_init (s);
|
|
|
|
mpz_init (t);
|
|
|
|
mpz_gcdext (d, s, t, impl->x, z.impl->x);
|
|
|
|
return make_tuple (Z (STEAL, d),
|
|
|
|
Z (STEAL, s),
|
|
|
|
Z (STEAL, t));
|
|
|
|
}
|
|
|
|
|
2011-12-09 21:50:25 +01:00
|
|
|
static void show_ring () { printf ("Z"); }
|
|
|
|
void show_self () const { mpz_out_str (stdout, 10, impl->x); }
|
|
|
|
void display_self () const { show_self (); newline (); }
|
2011-12-22 21:35:49 +01:00
|
|
|
void write_self (writer &w) const { write (w, *impl); }
|
2011-12-09 21:50:25 +01:00
|
|
|
};
|