aboutsummaryrefslogtreecommitdiffhomepage
path: root/theories/NArith/Psqrt.v
blob: 1d85f14a201da468131f044cc82e4c688e71961a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
(************************************************************************)
(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010     *)
(*   \VV/  **************************************************************)
(*    //   *      This file is distributed under the terms of the       *)
(*         *       GNU Lesser General Public License Version 2.1        *)
(************************************************************************)

Require Import BinPos.

Open Scope positive_scope.

Definition Pleb x y :=
 match Pcompare x y Eq with Gt => false | _ => true end.

(** A Square Root function for positive numbers *)

(** We procede by blocks of two digits : if p is written qbb'
    then sqrt(p) will be sqrt(q)~0 or sqrt(q)~1.
    For deciding easily in which case we are, we store the remainder
    (as a positive_mask, since it can be null).
    Instead of copy-pasting the following code four times, we
    factorize as an auxiliary function, with f and g being either
    xO or xI depending of the initial digits.
    NB: (Pminus_mask (g (f 1)) 4) is a hack, morally it's g (f 0).
*)

Definition Psqrtrem_step (f g:positive->positive) p :=
 match p with
  | (s, IsPos r) =>
    let s' := s~0~1 in
    let r' := g (f r) in
    if Pleb s' r' then (s~1, Pminus_mask r' s')
    else (s~0, IsPos r')
  | (s,_)  => (s~0, Pminus_mask (g (f 1)) 4)
 end.

Fixpoint Psqrtrem p : positive * positive_mask :=
 match p with
  | 1 => (1,IsNul)
  | 2 => (1,IsPos 1)
  | 3 => (1,IsPos 2)
  | p~0~0 => Psqrtrem_step xO xO (Psqrtrem p)
  | p~0~1 => Psqrtrem_step xO xI (Psqrtrem p)
  | p~1~0 => Psqrtrem_step xI xO (Psqrtrem p)
  | p~1~1 => Psqrtrem_step xI xI (Psqrtrem p)
 end.

Definition Psqrt p := fst (Psqrtrem p).

(** An inductive relation for specifying sqrt results *)

Inductive PSQRT : positive*positive_mask -> positive -> Prop :=
 | PSQRT_exact : forall s x, x=s*s -> PSQRT (s,IsNul) x
 | PSQRT_approx : forall s r x, x=s*s+r -> r <= s~0 -> PSQRT (s,IsPos r) x.

(** Correctness proofs *)

Lemma Psqrtrem_step_spec : forall f g p x,
 (f=xO \/ f=xI) -> (g=xO \/ g=xI) ->
 PSQRT p x -> PSQRT (Psqrtrem_step f g p) (g (f x)).
Proof.
intros f g _ _ Hf Hg [ s _ -> | s r _ -> Hr ].
(* exact *)
unfold Psqrtrem_step.
destruct Hf,Hg; subst; simpl Pminus_mask;
 constructor; try discriminate; now rewrite Psquare_xO.
(* approx *)
assert (Hfg : forall p q, g (f (p+q)) = p~0~0 + g (f q))
 by (intros; destruct Hf, Hg; now subst).
unfold Psqrtrem_step. unfold Pleb.
case Pcompare_spec; [intros EQ | intros LT | intros GT].
(* - EQ *)
rewrite <- EQ. rewrite Pminus_mask_diag.
destruct Hg; subst g; try discriminate.
destruct Hf; subst f; try discriminate.
injection EQ; clear EQ; intros <-.
constructor. now rewrite Psquare_xI.
(* - LT *)
destruct (Pminus_mask_Gt (g (f r)) (s~0~1)) as (y & -> & H & _).
change Eq with (CompOpp Eq). now rewrite <- Pcompare_antisym, LT.
constructor.
rewrite Hfg, <- H. now rewrite Psquare_xI, Pplus_assoc.
apply Ple_lteq, Pcompare_p_Sq in Hr; change (r < s~1) in Hr.
apply Ple_lteq, Pcompare_p_Sq; change (y < s~1~1).
apply Pplus_lt_mono_l with (s~0~1).
rewrite H. simpl. rewrite Pplus_carry_spec, Pplus_diag. simpl.
set (s1:=s~1) in *; clearbody s1.
destruct Hf,Hg; subst; red; simpl;
  apply Hr || apply Pcompare_eq_Lt, Hr.
(* - GT *)
constructor.
rewrite Hfg. now rewrite Psquare_xO.
apply Ple_lteq, Pcompare_p_Sq, GT.
Qed.

Lemma Psqrtrem_spec : forall p, PSQRT (Psqrtrem p) p.
Proof.
fix 1.
 destruct p; try destruct p; try (constructor; easy);
  apply Psqrtrem_step_spec; auto.
Qed.

Lemma Psqrt_spec : forall p,
 let s := Psqrt p in s*s <= p < (Psucc s)*(Psucc s).
Proof.
 intros p. simpl.
 assert (H:=Psqrtrem_spec p).
 unfold Psqrt in *. destruct Psqrtrem as (s,rm); simpl.
 inversion_clear H; subst.
 (* exact *)
 split. red. rewrite Pcompare_refl. discriminate.
  apply Pmult_lt_mono; apply Pcompare_p_Sp.
 (* approx *)
 split.
 apply Ple_lteq; left. apply Plt_plus_r.
 rewrite (Pplus_one_succ_l).
 rewrite Pmult_plus_distr_r, !Pmult_plus_distr_l.
 rewrite !Pmult_1_r. simpl (1*s).
 rewrite <- Pplus_assoc, (Pplus_assoc s s), Pplus_diag, Pplus_assoc.
 rewrite (Pplus_comm (_+_)). apply Pplus_lt_mono_l.
 rewrite <- Pplus_one_succ_l. now apply Pcompare_p_Sq, Ple_lteq.
Qed.