(***********************************************************************) (* v * The Coq Proof Assistant / The Coq Development Team *) (* Z*Z := [b:Z] Cases a of | xH => if `(Zge_bool b 2)` then `(0,1)` else `(1,0)` | (xO a') => let (q,r) = (Zdiv_eucl_POS a' b) in if `(Zgt_bool b (r+r))` then `(q+q,r+r)` else `(q+q+1,r+r-b)` | (xI a') => let (q,r) = (Zdiv_eucl_POS a' b) in if `(Zgt_bool b (r+r+1))` then `(q+q,r+r+1)` else `(q+q+1,r+r+1-b)` end. (** Euclidean division of integers. Total function than returns (0,0) when dividing by 0. *) (* The pseudo-code is: if b = 0 : (0,0) if b <> 0 and a = 0 : (0,0) if b > 0 and a < 0 : let (q,r) = div_eucl_pos (-a) b in if r = 0 then (-q,0) else (-(q+1),b-r) if b < 0 and a < 0 : let (q,r) = div_eucl (-a) (-b) in (q,-r) if b < 0 and a > 0 : let (q,r) = div_eucl a (-b) in if r = 0 then (-q,0) else (-(q+1),b+r) *) Definition Zdiv_eucl [a,b:Z] : Z*Z := Cases a b of | ZERO _ => `(0,0)` | _ ZERO => `(0,0)` | (POS a') (POS _) => (Zdiv_eucl_POS a' b) | (NEG a') (POS _) => let (q,r) = (Zdiv_eucl_POS a' b) in Cases r of | ZERO => `(-q,0)` | _ => `(-(q+1),b-r)` end | (NEG a') (NEG b') => let (q,r) = (Zdiv_eucl_POS a' (POS b')) in `(q,-r)` | (POS a') (NEG b') => let (q,r) = (Zdiv_eucl_POS a' (POS b')) in Cases r of | ZERO => `(-q,0)` | _ => `(-(q+1),b+r)` end end. (** Division and modulo are projections of [Zdiv_eucl] *) Definition Zdiv [a,b:Z] : Z := let (q,_) = (Zdiv_eucl a b) in q. Definition Zmod [a,b:Z] : Z := let (_,r) = (Zdiv_eucl a b) in r. (* Tests: Eval Compute in `(Zdiv_eucl 7 3)`. Eval Compute in `(Zdiv_eucl (-7) 3)`. Eval Compute in `(Zdiv_eucl 7 (-3))`. Eval Compute in `(Zdiv_eucl (-7) (-3))`. *) (** Main division theorem. First a lemma for positive *) Lemma Z_div_mod_POS : (b:Z)`b > 0` -> (a:positive) let (q,r)=(Zdiv_eucl_POS a b) in `(POS a) = b*q + r`/\`0<=r 0` -> let (q,r) = (Zdiv_eucl a b) in `a = b*q + r` /\ `0<=r 0` -> (a:Z) { qr:Z*Z | let (q,r)=qr in `a=b*q+r` /\ `0 <= r < b` }. Proof. Intros b Hb a. Exists (Zdiv_eucl a b). Exact (Z_div_mod a b Hb). Qed. Implicits Zdiv_eucl_exist. Theorem Zdiv_eucl_extended : (b:Z)`b <> 0` -> (a:Z) { qr:Z*Z | let (q,r)=qr in `a=b*q+r` /\ `0 <= r < |b|` }. Proof. Intros b Hb a. Elim (Z_le_gt_dec `0` b);Intro Hb'. Cut `b>0`;[Intro Hb''|Omega]. Rewrite Zabs_eq;[Apply Zdiv_eucl_exist;Assumption|Assumption]. Cut `-b>0`;[Intro Hb''|Omega]. Elim (Zdiv_eucl_exist Hb'' a);Intros qr. Elim qr;Intros q r Hqr. Exists (pair ? ? `-q` r). Elim Hqr;Intros. Split. Rewrite <- Zmult_Zopp_left;Assumption. Rewrite Zabs_non_eq;[Assumption|Omega]. Qed. Implicits Zdiv_eucl_extended. (** Auxiliary lemmas about [Zdiv] and [Zmod] *) Lemma Z_div_mod_eq : (a,b:Z)`b > 0` -> `a = b * (Zdiv a b) + (Zmod a b)`. Proof. Unfold Zdiv Zmod. Intros a b Hb. Generalize (Z_div_mod a b Hb). Case (Zdiv_eucl); Tauto. Save. Lemma Z_mod_lt : (a,b:Z)`b > 0` -> `0 <= (Zmod a b) < b`. Proof. Unfold Zmod. Intros a b Hb. Generalize (Z_div_mod a b Hb). Case (Zdiv_eucl a b); Tauto. Save. Lemma Z_div_POS_ge0 : (b:Z)(a:positive) let (q,_) = (Zdiv_eucl_POS a b) in `q >= 0`. Proof. Induction a; Intros; Simpl. Generalize H; Case (Zdiv_eucl_POS p b); Simpl. Intros; Case (Zgt_bool b `z0+z0+1`); Simpl; Omega. Generalize H; Case (Zdiv_eucl_POS p b); Simpl. Intros; Case (Zgt_bool b `z0+z0`); Simpl; Omega. Case (Zge_bool b `2`); Simpl; Omega. Save. Lemma Z_div_ge0 : (a,b:Z)`b > 0` -> `a >= 0` -> `(Zdiv a b) >= 0`. Proof. Intros a b Hb; Unfold Zdiv Zdiv_eucl; Case a; Simpl; Intros. Case b; Simpl; Trivial. Generalize Hb; Case b; Try Trivial. Auto with zarith. Intros p0 Hp0; Generalize (Z_div_POS_ge0 (POS p0) p). Case (Zdiv_eucl_POS p (POS p0)); Simpl; Tauto. Intros; Discriminate. Elim H; Trivial. Save. Lemma Z_div_lt : (a,b:Z)`b >= 2` -> `a > 0` -> `(Zdiv a b) < a`. Proof. Intros. Cut `b > 0`; [Intro Hb | Omega]. Generalize (Z_div_mod a b Hb). Cut `a >= 0`; [Intro Ha | Omega]. Generalize (Z_div_ge0 a b Hb Ha). Unfold Zdiv; Case (Zdiv_eucl a b); Intros q r H1 [H2 H3]. Cut `a >= 2*q` -> `q < a`; [ Intro h; Apply h; Clear h | Intros; Omega ]. Apply Zge_trans with `b*q`. Omega. Auto with zarith. Save. (** Syntax *) Grammar znatural expr2 : constr := expr_div [ expr2($p) "/" expr2($c) ] -> [ (Zdiv $p $c) ] | expr_mod [ expr2($p) "%" expr2($c) ] -> [ (Zmod $p $c) ] . Syntax constr level 6: Zdiv [ (Zdiv $n1 $n2) ] -> [ [ "`"(ZEXPR $n1):E "/" [0 0] (ZEXPR $n2):L "`"] ] | Zmod [ (Zmod $n1 $n2) ] -> [ [ "`"(ZEXPR $n1):E "%" [0 0] (ZEXPR $n2):L "`"] ] | Zdiv_inside [ << (ZEXPR <<(Zdiv $n1 $n2)>>) >> ] -> [ (ZEXPR $n1):E "/" [0 0] (ZEXPR $n2):L ] | Zmod_inside [ << (ZEXPR <<(Zmod $n1 $n2)>>) >> ] -> [ (ZEXPR $n1):E "%" [0 0] (ZEXPR $n2):L ] .