Section EQ_MODULO.
Variable modul: Z.
Hypothesis modul_pos: modul > 0.
Definition eqmod (x y: Z) : Prop := exists k, x = k * modul + y.
End EQ_MODULO.
(** ** Fast normalization modulo [2^n] *)
Fixpoint P_mod_two_p (p: positive) (n: nat) {struct n} : Z :=
match n with
| O => 0
| S m =>
match p with
| xH => 1
| xO q => Z.double (P_mod_two_p q m)
| xI q => Z.succ_double (P_mod_two_p q m)
end
end.
Definition Z_mod_two_p (x: Z) (n: nat) : Z :=
match x with
| Z0 => 0
| Zpos p => P_mod_two_p p n
| Zneg p => let r := P_mod_two_p p n in if zeq r 0 then 0 else two_power_nat n - r
end.
(** ** Bit-level operations and properties *)
(** Shift [x] left by one and insert [b] as the low bit of the result. *)
Definition Zshiftin (b: bool) (x: Z) : Z :=
if b then Z.succ_double x else Z.double x.
Remark Ztestbit_0: forall n, Z.testbit 0 n = false.
Proof Z.testbit_0_l.
Remark Ztestbit_1: forall n, Z.testbit 1 n = zeq n 0.
Remark Ztestbit_m1: forall n, 0 <= n -> Z.testbit (-1) n = true.
Remark Zshiftin_spec:
forall b x, Zshiftin b x = 2 * x + (if b then 1 else 0).
Remark Zshiftin_inj:
forall b1 x1 b2 x2,
Zshiftin b1 x1 = Zshiftin b2 x2 -> b1 = b2 /\ x1 = x2.
Remark Zdecomp:
forall x, x = Zshiftin (Z.odd x) (Z.div2 x).
Remark Ztestbit_shiftin:
forall b x n,
0 <= n ->
Z.testbit (Zshiftin b x) n = if zeq n 0 then b else Z.testbit x (Z.pred n).
Remark Ztestbit_shiftin_base:
forall b x, Z.testbit (Zshiftin b x) 0 = b.
Remark Ztestbit_shiftin_succ:
forall b x n, 0 <= n -> Z.testbit (Zshiftin b x) (Z.succ n) = Z.testbit x n.
(** ** Bit-wise decomposition ([Z.testbit]) *)
Remark Ztestbit_eq:
forall n x, 0 <= n ->
Z.testbit x n = if zeq n 0 then Z.odd x else Z.testbit (Z.div2 x) (Z.pred n).
Remark Ztestbit_base:
forall x, Z.testbit x 0 = Z.odd x.
Remark Ztestbit_succ:
forall n x, 0 <= n -> Z.testbit x (Z.succ n) = Z.testbit (Z.div2 x) n.
Proof Z.bits_inj'.
(** ** Zero and sign extensions *)
(** In pseudo-code: << Fixpoint Zzero_ext (n: Z) (x: Z) : Z := if zle n 0 then 0 else Zshiftin (Z.odd x) (Zzero_ext (Z.pred n) (Z.div2 x)). Fixpoint Zsign_ext (n: Z) (x: Z) : Z := if zle n 1 then if Z.odd x then -1 else 0 else Zshiftin (Z.odd x) (Zzero_ext (Z.pred n) (Z.div2 x)). >> We encode this [nat]-like recursion using the [Z.iter] iteration function, in order to make the [Zzero_ext] and [Zsign_ext] functions efficiently executable within Coq. *)
Definition Zzero_ext (n: Z) (x: Z) : Z :=
Z.iter n
(fun rec x => Zshiftin (Z.odd x) (rec (Z.div2 x)))
(fun x => 0)
x.
Definition Zsign_ext (n: Z) (x: Z) : Z :=
Z.iter (Z.pred n)
(fun rec x => Zshiftin (Z.odd x) (rec (Z.div2 x)))
(fun x => if Z.odd x && zlt 0 n then -1 else 0)
x.
(** [Zzero_ext n x] is [x modulo 2^n] *)
(** [Zzero_ext n x] is the unique integer congruent to [x] modulo [2^n] in the range [0...2^n-1]. *)
(** Relation between [Zsign_ext n x] and (Zzero_ext n x] *)
(** [Zsign_ext n x] is the unique integer congruent to [x] modulo [2^n] in the range [-2^(n-1)...2^(n-1) - 1]. *)
(** ** Decomposition of a number as a sum of powers of two. *)
Fixpoint Z_one_bits (n: nat) (x: Z) (i: Z) {struct n}: list Z :=
match n with
| O => nil
| S m =>
if Z.odd x
then i :: Z_one_bits m (Z.div2 x) (i+1)
else Z_one_bits m (Z.div2 x) (i+1)
end.
Fixpoint powerserie (l: list Z): Z :=
match l with
| nil => 0
| x :: xs => two_p x + powerserie xs
end.
Remark Z_one_bits_zero:
forall n i, Z_one_bits n 0 i = nil.
Remark Z_one_bits_two_p:
forall n x i,
0 <= x < Z.of_nat n ->
Z_one_bits n (two_p x) i = (i + x) :: nil.
(** ** Recognition of powers of two *)
Fixpoint P_is_power2 (p: positive) : bool :=
match p with
| xH => true
| xO q => P_is_power2 q
| xI q => false
end.
Definition Z_is_power2 (x: Z) : option Z :=
match x with
| Z0 => None
| Zpos p => if P_is_power2 p then Some (Z.log2 x) else None
| Zneg _ => None
end.
Remark P_is_power2_sound:
forall p, P_is_power2 p = true -> Z.pos p = two_p (Z.log2 (Z.pos p)).
Definition Z_is_power2m1 (x: Z) : option Z := Z_is_power2 (Z.succ x).
(** ** Relation between bitwise operations and multiplications / divisions by powers of 2 *)
(** Left shifts and multiplications by powers of 2. *)

Lemma Zshiftl_mul_two_p:
forall x n, 0 <= n -> Z.shiftl x n = x * two_p n.