(** * Powers of 2 *)

  (** For the powers of two, that will be widely used, a more direct
      calculus is possible. [shift n m] computes [2^n * m], i.e.
      [m] shifted by [n] positions *)

  Definition shift_nat (n:nat) (z:positive) := nat_rect _ z (fun _ => xO) n.Definition shift_pos (n z:positive) := Pos.iter xO z n.Definition shift (n:Z) (z:positive) :=
    match n with
      | Z0 => z
      | Zpos p => Pos.iter xO z p
      | Zneg p => z
    end.Definition two_power_nat (n:nat) := Zpos (shift_nat n 1).Definition two_power_pos (x:positive) := Zpos (shift_pos x 1).Definition two_p (x:Z) :=
    match x with
      | Z0 => 1
      | Zpos y => two_power_pos y
      | Zneg y => 0
    end.

(* Specifications: *)
Lemma shift_nat_equiv n p : shift_nat n p = Pos.shiftl_nat p n.
Lemma shift_pos_equiv n p : shift_pos n p = Pos.shiftl p (Npos n).
Lemma shift_equiv n p : 0<=n -> Zpos (shift n p) = Z.shiftl (Zpos p) n.
Lemma two_power_nat_equiv n : two_power_nat n = 2 ^ (Z.of_nat n).
Lemma two_power_pos_equiv p : two_power_pos p = 2 ^ Zpos p.
Lemma two_p_equiv x : two_p x = 2 ^ x.
Lemma two_power_nat_S n : two_power_nat (S n) = 2 * two_power_nat n.
Lemma shift_nat_plus n m x : shift_nat (n + m) x = shift_nat n (shift_nat m x).
Theorem shift_nat_correct n x : Zpos (shift_nat n x) = Zpower_nat 2 n * Zpos x.
Theorem two_power_nat_correct n : two_power_nat n = Zpower_nat 2 n.
Lemma shift_pos_nat p x : shift_pos p x = shift_nat (Pos.to_nat p) x.
Lemma two_power_pos_nat p : two_power_pos p = two_power_nat (Pos.to_nat p).
Theorem shift_pos_correct p x : Zpos (shift_pos p x) = Z.pow_pos 2 p * Zpos x.
Theorem two_power_pos_correct x : two_power_pos x = Z.pow_pos 2 x.
Theorem two_power_pos_is_exp x y : two_power_pos (x + y) = two_power_pos x * two_power_pos y.
Lemma two_p_correct x : two_p x = 2^x.
Theorem two_p_is_exp x y : 0 <= x -> 0 <= y -> two_p (x + y) = two_p x * two_p y.
Lemma two_p_gt_ZERO x : 0 <= x -> two_p x > 0.
Lemma two_p_S x : 0 <= x -> two_p (Z.succ x) = 2 * two_p x.
Lemma two_p_pred x : 0 <= x -> two_p (Z.pred x) < two_p x.