(** * A direct way to compute Z.modulo *)

Fixpoint Zmod_POS (a : positive) (b : Z) : Z  :=
  match a with
   | xI a' =>
      let r := Zmod_POS a' b in
      let r' := (2 * r + 1) in
      if r' <? b then r' else (r' - b)
   | xO a' =>
      let r := Zmod_POS a' b in
      let r' := (2 * r) in
      if r' <? b then r' else (r' - b)
   | xH => if 2 <=? b then 1 else 0
  end.Definition Zmod' a b :=
  match a with
   | Z0 => 0
   | Zpos a' =>
      match b with
       | Z0 => a
       | Zpos _ => Zmod_POS a' b
       | Zneg b' =>
          let r := Zmod_POS a' (Zpos b') in
          match r  with Z0 =>  0 |  _  =>   b + r end
      end
   | Zneg a' =>
      match b with
       | Z0 => a
       | Zpos _ =>
          let r := Zmod_POS a' b in
          match r with Z0 =>  0 | _  =>  b - r end
       | Zneg b' => - (Zmod_POS a' (Zpos b'))
      end
  end.

(* Specifications: *)
Theorem Zmod_POS_correct a b : Zmod_POS a b = snd (Z.pos_div_eucl a b).
Theorem Zmod'_correct: forall a b, Zmod' a b = a mod b.
Theorem Zdiv_eucl_extended : forall b:Z, b <> 0 -> forall a:Z, {qr : Z * Z | let (q, r) := qr in a = b * q + r /\ 0 <= r < Z.abs b}.
Lemma mod_id_iff a b : a mod b = a <-> 0 <= a < b \/ b = 0 \/ b < a <= 0.
Lemma gcd_mod_l a b : Z.gcd (a mod b) b = Z.gcd a b.
Lemma gcd_mod_r a b : Z.gcd a (b mod a) = Z.gcd a b.
Lemma mod_pow_l a b c : (a mod c)^b mod c = ((a ^ b) mod c).
Lemma cong_iff_0 a b m : a mod m = b mod m <-> (a - b) mod m = 0.
Lemma cong_iff_ex a b m : a mod m = b mod m <-> exists n, a - b = n * m.
Lemma mod_mod_divide a b c : (c | b) -> (a mod b) mod c = a mod c.
Lemma mod_opp_mod_opp a b : - (-a mod b) mod b = a mod b.
Lemma mod_mod_opp_r a b : (a mod - b) mod b = a mod b.
Lemma mod_opp_r_mod a b : (a mod b) mod - b = a mod - b.
Lemma mod_mod_abs_r a b : (a mod Z.abs b) mod b = a mod b.
Lemma mod_abs_r_mod a b : (a mod b) mod Z.abs b = a mod Z.abs b.