(** A generalized gcd: it additionnally keeps track of the divisors. *)

Fixpoint Zggcdn (n:nat) : Z -> Z -> (Z*(Z*Z)) := fun a b => 
 match n with 
  | O => (1,(a,b))   (*(Zabs b,(0,Zsgn b))*)
  | S n => match a with 
     | Z0 => (Zabs b,(0,Zsgn b))
     | Zpos _ => 
               let (q,r) := Zdiv_eucl b a in   (* b = q*a+r *)
               let (g,p) := Zggcdn n r a in 
               let (rr,aa) := p in        (* r = g *rr /\ a = g * aa *)
               (g,(aa,q*aa+rr))
     | Zneg a => 
               let (q,r) := Zdiv_eucl b (Zpos a) in  (* b = q*(-a)+r *)
               let (g,p) := Zggcdn n r (Zpos a) in 
               let (rr,aa) := p in         (* r = g*rr /\ (-a) = g * aa *)  
               (g,(-aa,q*aa+rr))
     end
   end.Definition Zggcd a b : Z * (Z * Z) := Zggcdn (Zgcd_bound a) a b.

(* Specifications: *)
Lemma Zggcdn_gcdn : forall n a b, fst (Zggcdn n a b) = Zgcdn n a b.
Lemma Zggcd_gcd : forall a b, fst (Zggcd a b) = Zgcd a b.
Lemma Zggcdn_correct_divisors : forall n a b, let (g,p) := Zggcdn n a b in let (aa,bb):=p in a=g*aa /\ b=g*bb.
Lemma Zggcd_correct_divisors : forall a b, let (g,p) := Zggcd a b in let (aa,bb):=p in a=g*aa /\ b=g*bb.