(** * Euclid gcd algorithm *) 

(** This was previously part of Coq standard library (in Znumtheory). 
   But the new binary algorithm used there is much faster and also easier 
   to prove correct (for the variant that is executable in coq). 
*)

(** In this first variant, we use an explicit measure in [nat], and we 
  prove later that using [2(d+1)] is enough, where [d] is the number of 
  binary digits of the first argument. *)

Fixpoint Zgcdn (n:nat) : Z -> Z -> Z := fun a b => 
 match n with 
  | O => 1 (* arbitrary, since n should be big enough *)
  | S n => match a with 
     | Z0 => Zabs b
     | Zpos _ => Zgcdn n (Zmod b a) a
     | Zneg a => Zgcdn n (Zmod b (Zpos a)) (Zpos a)
     end
   end.(* For technical reason, we don't use [Ndigit.Psize] but this 
   ad-hoc version: [Psize p = S (Psiz p)]. *)

Fixpoint Psiz (p:positive) : nat := 
  match p with 
    | xH => O
    | xI p => S (Psiz p) 
    | xO p => S (Psiz p)
  end.Definition Zgcd_bound (a:Z) := match a with 
 | Z0 => S O
 | Zpos p => let n := Psiz p in S (S (n+n))
 | Zneg p => let n := Psiz p in S (S (n+n))
end.Definition Zgcd a b := Zgcdn (Zgcd_bound a) a b.

(* Specifications: *)
Lemma Zgcdn_is_pos : forall n a b, 0 <= Zgcdn n a b.
Lemma Zgcd_is_pos : forall a b, 0 <= Zgcd a b.
Lemma Zis_gcd_0_abs : forall b, Zis_gcd 0 b (Zabs b) /\ Zabs b >= 0 /\ 0 = Zabs b * 0 /\ b = Zabs b * Zsgn b.
Lemma Zgcdn_linear_bound : forall n a b, Zabs a < Z_of_nat n -> Zis_gcd a b (Zgcdn n a b).