Built with Alectryon, running Coq+SerAPI v8.10.0+0.7.0. Coq sources are in this panel; goals and messages will appear in the other. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑ Ctrl+↓ to navigate, Ctrl+🖱️ to focus.
(************************************************************************) (* * The Coq Proof Assistant / The Coq Development Team *) (* v * INRIA, CNRS and contributors - Copyright 1999-2018 *) (* <O___,, * (see CREDITS file for the list of authors) *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (* * (see LICENSE file for the text of the license) *) (************************************************************************) Require Import Wf_nat ZArith_base Omega Zcomplements. Require Export Zpow_def. Local Open Scope Z_scope.
Nota : this file is mostly deprecated. The definition of Z.pow
and its usual properties are now provided by module BinInt.Z.
Powers of 2 are also available there (see Z.shiftl and Z.shiftr).
Only remain here:
- Zpower_nat : a power function with a nat exponent
- old-style powers of two, such as two_p
- Zdiv_rest : a division + modulo when the divisor is a power of 2
Zpower_nat z n is the n-th power of z when n is an unary
integer (type nat) and z a signed integer (type Z)
Definition Zpower_nat (z:Z) := nat_rect _ 1 (fun _ => Z.mul z).z:ZZpower_nat z 0 = 1reflexivity. Qed.z:ZZpower_nat z 0 = 1n:natz:ZZpower_nat z (S n) = z * Zpower_nat z nreflexivity. Qed.n:natz:ZZpower_nat z (S n) = z * Zpower_nat z n
Zpower_nat_is_exp says Zpower_nat is a morphism for
plus : nat→nat→nat and Z.mul : Z→Z→Z
forall (n m : nat) (z : Z), Zpower_nat z (n + m) = Zpower_nat z n * Zpower_nat z mforall (n m : nat) (z : Z), Zpower_nat z (n + m) = Zpower_nat z n * Zpower_nat z mforall (m : nat) (z : Z), Zpower_nat z (0 + m) = Zpower_nat z 0 * Zpower_nat z mn:natIHn:forall (m : nat) (z : Z), Zpower_nat z (n + m) = Zpower_nat z n * Zpower_nat z mforall (m : nat) (z : Z), Zpower_nat z (S n + m) = Zpower_nat z (S n) * Zpower_nat z mforall (m : nat) (z : Z), Zpower_nat z (0 + m) = Zpower_nat z 0 * Zpower_nat z mnow rewrite Zpower_nat_0_r, Z.mul_1_l.m:natz:ZZpower_nat z (0 + m) = Zpower_nat z 0 * Zpower_nat z mn:natIHn:forall (m : nat) (z : Z), Zpower_nat z (n + m) = Zpower_nat z n * Zpower_nat z mforall (m : nat) (z : Z), Zpower_nat z (S n + m) = Zpower_nat z (S n) * Zpower_nat z mn:natIHn:forall (m0 : nat) (z0 : Z), Zpower_nat z0 (n + m0) = Zpower_nat z0 n * Zpower_nat z0 m0m:natz:ZZpower_nat z (S n + m) = Zpower_nat z (S n) * Zpower_nat z mnow rewrite IHn, Z.mul_assoc. Qed.n:natIHn:forall (m0 : nat) (z0 : Z), Zpower_nat z0 (n + m0) = Zpower_nat z0 n * Zpower_nat z0 m0m:natz:Zz * Zpower_nat z (n + m) = z * Zpower_nat z n * Zpower_nat z m
Conversions between powers of unary and binary integers
z:Zp:positiveZ.pow_pos z p = Zpower_nat z (Pos.to_nat p)apply Pos2Nat.inj_iter. Qed.z:Zp:positiveZ.pow_pos z p = Zpower_nat z (Pos.to_nat p)z:Zn:natZpower_nat z n = z ^ Z.of_nat nz:Zn:natZpower_nat z n = z ^ Z.of_nat nz:ZZpower_nat z 0 = z ^ Z.of_nat 0z:Zn:natIHn:Zpower_nat z n = z ^ Z.of_nat nZpower_nat z (S n) = z ^ Z.of_nat (S n)z:Zn:natIHn:Zpower_nat z n = z ^ Z.of_nat nZpower_nat z (S n) = z ^ Z.of_nat (S n)z:Zn:natIHn:Zpower_nat z n = z ^ Z.of_nat nz * Zpower_nat z n = z * z ^ Z.of_nat nz:Zn:natIHn:Zpower_nat z n = z ^ Z.of_nat n0 <= Z.of_nat napply Nat2Z.is_nonneg. Qed.z:Zn:natIHn:Zpower_nat z n = z ^ Z.of_nat n0 <= Z.of_nat nz, n:Z0 <= n -> z ^ n = Zpower_nat z (Z.abs_nat n)z, n:Z0 <= n -> z ^ n = Zpower_nat z (Z.abs_nat n)now rewrite Zpower_nat_Z, Zabs2Nat.id_abs, Z.abs_eq. Qed.z, n:ZH:0 <= nz ^ n = Zpower_nat z (Z.abs_nat n)
The function (Z.pow_pos z) is a morphism
for Pos.add : positive→positive→positive and Z.mul : Z→Z→Z
n, m:positivez:ZZ.pow_pos z (n + m) = Z.pow_pos z n * Z.pow_pos z mnow apply (Z.pow_add_r z (Zpos n) (Zpos m)). Qed. Hint Immediate Zpower_nat_is_exp Zpower_pos_is_exp : zarith. Hint Unfold Z.pow_pos Zpower_nat: zarith.n, m:positivez:ZZ.pow_pos z (n + m) = Z.pow_pos z n * Z.pow_pos z mx, n, m:Zn >= 0 -> m >= 0 -> x ^ (n + m) = x ^ n * x ^ mx, n, m:Zn >= 0 -> m >= 0 -> x ^ (n + m) = x ^ n * x ^ mapply Z.pow_add_r. Qed. Section Powers_of_2.x, n, m:Z0 <= n -> 0 <= m -> x ^ (n + m) = x ^ n * x ^ m
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.
Equivalence with notions defined in BinInt
n:natp:positiveshift_nat n p = Pos.shiftl_nat p nreflexivity. Qed.n:natp:positiveshift_nat n p = Pos.shiftl_nat p nn, p:positiveshift_pos n p = Pos.shiftl p (N.pos n)reflexivity. Qed.n, p:positiveshift_pos n p = Pos.shiftl p (N.pos n)n:Zp:positive0 <= n -> Z.pos (shift n p) = Z.shiftl (Z.pos p) nn:Zp:positive0 <= n -> Z.pos (shift n p) = Z.shiftl (Z.pos p) np:positive0 <= 0 -> Z.pos (shift 0 p) = Z.shiftl (Z.pos p) 0p0, p:positive0 <= Z.pos p0 -> Z.pos (shift (Z.pos p0) p) = Z.shiftl (Z.pos p) (Z.pos p0)p0, p:positive0 <= Z.neg p0 -> Z.pos (shift (Z.neg p0) p) = Z.shiftl (Z.pos p) (Z.neg p0)trivial.p:positive0 <= 0 -> Z.pos (shift 0 p) = Z.shiftl (Z.pos p) 0p0, p:positive0 <= Z.pos p0 -> Z.pos (shift (Z.pos p0) p) = Z.shiftl (Z.pos p) (Z.pos p0)now apply Pos.iter_swap_gen.p0, p:positiveH:0 <= Z.pos p0Z.pos (Pos.iter xO p p0) = Pos.iter (Z.mul 2) (Z.pos p) p0now destruct 1. Qed.p0, p:positive0 <= Z.neg p0 -> Z.pos (shift (Z.neg p0) p) = Z.shiftl (Z.pos p) (Z.neg p0)n:nattwo_power_nat n = 2 ^ Z.of_nat nn:nattwo_power_nat n = 2 ^ Z.of_nat ntwo_power_nat 0 = 2 ^ Z.of_nat 0n:natIHn:two_power_nat n = 2 ^ Z.of_nat ntwo_power_nat (S n) = 2 ^ Z.of_nat (S n)trivial.two_power_nat 0 = 2 ^ Z.of_nat 0now rewrite Nat2Z.inj_succ, Z.pow_succ_r, <- IHn by apply Nat2Z.is_nonneg. Qed.n:natIHn:two_power_nat n = 2 ^ Z.of_nat ntwo_power_nat (S n) = 2 ^ Z.of_nat (S n)p:positivetwo_power_pos p = 2 ^ Z.pos pnow apply Pos.iter_swap_gen. Qed.p:positivetwo_power_pos p = 2 ^ Z.pos px:Ztwo_p x = 2 ^ xx:Ztwo_p x = 2 ^ xapply two_power_pos_equiv. Qed.p:positivetwo_p (Z.pos p) = 2 ^ Z.pos p
Properties of these old versions of powers of two
n:nattwo_power_nat (S n) = 2 * two_power_nat nreflexivity. Qed.n:nattwo_power_nat (S n) = 2 * two_power_nat nn, m:natx:positiveshift_nat (n + m) x = shift_nat n (shift_nat m x)induction n; simpl; now f_equal. Qed.n, m:natx:positiveshift_nat (n + m) x = shift_nat n (shift_nat m x)n:natx:positiveZ.pos (shift_nat n x) = Zpower_nat 2 n * Z.pos xn:natx:positiveZ.pos (shift_nat n x) = Zpower_nat 2 n * Z.pos xx:positiveZ.pos (shift_nat 0 x) = Zpower_nat 2 0 * Z.pos xn:natx:positiveIHn:Z.pos (shift_nat n x) = Zpower_nat 2 n * Z.pos xZ.pos (shift_nat (S n) x) = Zpower_nat 2 (S n) * Z.pos xtrivial.x:positiveZ.pos (shift_nat 0 x) = Zpower_nat 2 0 * Z.pos xnow rewrite Zpower_nat_succ_r, <- Z.mul_assoc, <- IHn. Qed.n:natx:positiveIHn:Z.pos (shift_nat n x) = Zpower_nat 2 n * Z.pos xZ.pos (shift_nat (S n) x) = Zpower_nat 2 (S n) * Z.pos xn:nattwo_power_nat n = Zpower_nat 2 nnow rewrite two_power_nat_equiv, Zpower_nat_Z. Qed.n:nattwo_power_nat n = Zpower_nat 2 np, x:positiveshift_pos p x = shift_nat (Pos.to_nat p) xapply Pos2Nat.inj_iter. Qed.p, x:positiveshift_pos p x = shift_nat (Pos.to_nat p) xp:positivetwo_power_pos p = two_power_nat (Pos.to_nat p)p:positivetwo_power_pos p = two_power_nat (Pos.to_nat p)now rewrite shift_pos_nat. Qed.p:positiveZ.pos (shift_pos p 1) = two_power_nat (Pos.to_nat p)p, x:positiveZ.pos (shift_pos p x) = Z.pow_pos 2 p * Z.pos xnow rewrite shift_pos_nat, Zpower_pos_nat, shift_nat_correct. Qed.p, x:positiveZ.pos (shift_pos p x) = Z.pow_pos 2 p * Z.pos xx:positivetwo_power_pos x = Z.pow_pos 2 xapply two_power_pos_equiv. Qed.x:positivetwo_power_pos x = Z.pow_pos 2 xx, y:positivetwo_power_pos (x + y) = two_power_pos x * two_power_pos yx, y:positivetwo_power_pos (x + y) = two_power_pos x * two_power_pos ynow apply (Z.pow_add_r 2 (Zpos x) (Zpos y)). Qed.x, y:positive2 ^ Z.pos (x + y) = 2 ^ Z.pos x * 2 ^ Z.pos yProof (two_p_equiv x).x:Ztwo_p x = 2 ^ xx, y:Z0 <= x -> 0 <= y -> two_p (x + y) = two_p x * two_p yx, y:Z0 <= x -> 0 <= y -> two_p (x + y) = two_p x * two_p yapply Z.pow_add_r. Qed.x, y:Z0 <= x -> 0 <= y -> 2 ^ (x + y) = 2 ^ x * 2 ^ yx:Z0 <= x -> two_p x > 0x:Z0 <= x -> two_p x > 0x:Z0 <= x -> 0 < two_p xnow apply Z.pow_pos_nonneg. Qed.x:Z0 <= x -> 0 < 2 ^ xx:Z0 <= x -> two_p (Z.succ x) = 2 * two_p xx:Z0 <= x -> two_p (Z.succ x) = 2 * two_p xnow apply Z.pow_succ_r. Qed.x:Z0 <= x -> 2 ^ Z.succ x = 2 * 2 ^ xx:Z0 <= x -> two_p (Z.pred x) < two_p xx:Z0 <= x -> two_p (Z.pred x) < two_p xx:Z0 <= x -> 2 ^ Z.pred x < 2 ^ xapply Z.pow_lt_mono_r; auto with zarith. Qed. End Powers_of_2. Hint Resolve two_p_gt_ZERO: zarith. Hint Immediate two_p_pred two_p_S: zarith. Section power_div_with_rest.x:ZH:0 <= x2 ^ Z.pred x < 2 ^ x
To x:Z and p:positive, q,r are associated such that
x = 2^p.q + r and 0 ≤ r < 2^p
Invariant: d×q + r = d'×q + r ∧ d' = 2*d ∧ 0<=r<d ∧ 0<=r'<d'
Definition Zdiv_rest_aux (qrd:Z * Z * Z) := let '(q,r,d) := qrd in (match q with | Z0 => (0, r) | Zpos xH => (0, d + r) | Zpos (xI n) => (Zpos n, d + r) | Zpos (xO n) => (Zpos n, r) | Zneg xH => (-1, d + r) | Zneg (xI n) => (Zneg n - 1, d + r) | Zneg (xO n) => (Zneg n, r) end, 2 * d). Definition Zdiv_rest (x:Z) (p:positive) := let (qr, d) := Pos.iter Zdiv_rest_aux (x, 0, 1) p in qr.x:Zp:positivelet (_, d) := Pos.iter Zdiv_rest_aux (x, 0, 1) p in d = two_power_pos px:Zp:positivelet (_, d) := Pos.iter Zdiv_rest_aux (x, 0, 1) p in d = two_power_pos px:Zp:positivelet (_, d) := nat_rect (fun _ : nat => (Z * Z * Z)%type) (x, 0, 1) (fun _ : nat => Zdiv_rest_aux) (Pos.to_nat p) in d = two_power_nat (Pos.to_nat p)x:Zp:positiven:natIHn:let (_, d) := nat_rect (fun _ : nat => (Z * Z * Z)%type) (x, 0, 1) (fun _ : nat => Zdiv_rest_aux) n in d = two_power_nat nlet (_, d) := Zdiv_rest_aux (nat_rect (fun _ : nat => (Z * Z * Z)%type) (x, 0, 1) (fun _ : nat => Zdiv_rest_aux) n) in d = two_power_nat (S n)x:Zp:positiven:natq, r, d:ZIHn:d = two_power_nat nlet (_, d0) := Zdiv_rest_aux (q, r, d) in d0 = two_power_nat (S n)rewrite two_power_nat_S; now f_equal. Qed.x:Zp:positiven:natq, r, d:ZIHn:d = two_power_nat n2 * d = two_power_nat (S n)x:Zp:positivelet '(q, r, d) := Pos.iter Zdiv_rest_aux (x, 0, 1) p in x = q * d + r /\ 0 <= r < dx:Zp:positivelet '(q, r, d) := Pos.iter Zdiv_rest_aux (x, 0, 1) p in x = q * d + r /\ 0 <= r < dx:Zp:positiveforall x0 : Z * Z * Z, (let '(q, r, d) := x0 in x = q * d + r /\ 0 <= r < d) -> let '(q, r, d) := Zdiv_rest_aux x0 in x = q * d + r /\ 0 <= r < dx:Zp:positiveq, r, d:ZH:x = q * d + rH':0 <= r < dlet '(q0, r0, d0) := Zdiv_rest_aux (q, r, d) in x = q0 * d0 + r0 /\ 0 <= r0 < d0x:Zp:positiveq, r, d:ZH:x = q * d + rH':0 <= r < dlet '(q0, r0) := match q with | 0 => (0, r) | Z.pos (n~1)%positive => (Z.pos n, d + r) | Z.pos (n~0)%positive => (Z.pos n, r) | 1 => (0, d + r) | Z.neg (n~1)%positive => (Z.neg n - 1, d + r) | Z.neg (n~0)%positive => (Z.neg n, r) | -1 => (-1, d + r) end in x = q0 * (2 * d) + r0 /\ 0 <= r0 < 2 * dx:Zp, q:positiver, d:ZH:x = Z.pos q~1 * d + rH':0 <= r < dx = Z.pos q * (2 * d) + (d + r) /\ 0 <= d + r < 2 * dx:Zp, q:positiver, d:ZH:x = Z.pos q~0 * d + rH':0 <= r < dx = Z.pos q * (2 * d) + r /\ 0 <= r < 2 * dx:Zp, q:positiver, d:ZH:x = Z.neg q~1 * d + rH':0 <= r < dx = (Z.neg q - 1) * (2 * d) + (d + r) /\ 0 <= d + r < 2 * dx:Zp, q:positiver, d:ZH:x = Z.neg q~0 * d + rH':0 <= r < dx = Z.neg q * (2 * d) + r /\ 0 <= r < 2 * dx:Zp, q:positiver, d:ZH:x = Z.pos q~1 * d + rH':0 <= r < dx = Z.pos q * (2 * d) + (d + r) /\ 0 <= d + r < 2 * dx:Zp, q:positiver, d:ZH:x = 2 * Z.pos q * d + 1 * d + rH':0 <= r < dx = Z.pos q * (2 * d) + (d + r) /\ 0 <= d + r < 2 * domega.x:Zp, q:positiver, d:ZH:x = 2 * Z.pos q * d + 1 * d + rH':0 <= r < dx = 2 * Z.pos q * d + (d + r) /\ 0 <= d + r < 2 * dx:Zp, q:positiver, d:ZH:x = Z.pos q~0 * d + rH':0 <= r < dx = Z.pos q * (2 * d) + r /\ 0 <= r < 2 * dx:Zp, q:positiver, d:ZH:x = 2 * Z.pos q * d + rH':0 <= r < dx = Z.pos q * (2 * d) + r /\ 0 <= r < 2 * domega.x:Zp, q:positiver, d:ZH:x = 2 * Z.pos q * d + rH':0 <= r < dx = 2 * Z.pos q * d + r /\ 0 <= r < 2 * dx:Zp, q:positiver, d:ZH:x = Z.neg q~1 * d + rH':0 <= r < dx = (Z.neg q - 1) * (2 * d) + (d + r) /\ 0 <= d + r < 2 * dx:Zp, q:positiver, d:ZH:x = 2 * Z.neg q * d - 1 * d + rH':0 <= r < dx = (Z.neg q - 1) * (2 * d) + (d + r) /\ 0 <= d + r < 2 * domega.x:Zp, q:positiver, d:ZH:x = 2 * Z.neg q * d - 1 * d + rH':0 <= r < dx = 2 * Z.neg q * d - 1 * (2 * d) + (d + r) /\ 0 <= d + r < 2 * dx:Zp, q:positiver, d:ZH:x = Z.neg q~0 * d + rH':0 <= r < dx = Z.neg q * (2 * d) + r /\ 0 <= r < 2 * dx:Zp, q:positiver, d:ZH:x = 2 * Z.neg q * d + rH':0 <= r < dx = Z.neg q * (2 * d) + r /\ 0 <= r < 2 * domega. Qed.x:Zp, q:positiver, d:ZH:x = 2 * Z.neg q * d + rH':0 <= r < dx = 2 * Z.neg q * d + r /\ 0 <= r < 2 * d
Old-style rich specification by proof of existence
Inductive Zdiv_rest_proofs (x:Z) (p:positive) : Set := Zdiv_rest_proof : forall q r:Z, x = q * two_power_pos p + r -> 0 <= r -> r < two_power_pos p -> Zdiv_rest_proofs x p.x:Zp:positiveZdiv_rest_proofs x px:Zp:positiveZdiv_rest_proofs x px:Zp:positive(let '(q, r, d) := Pos.iter Zdiv_rest_aux (x, 0, 1) p in x = q * d + r /\ 0 <= r < d) -> (let (_, d) := Pos.iter Zdiv_rest_aux (x, 0, 1) p in d = two_power_pos p) -> Zdiv_rest_proofs x px:Zp:positiveq, r, d:Zx = q * d + r /\ 0 <= r < d -> d = two_power_pos p -> Zdiv_rest_proofs x pnow exists q r. Qed.x:Zp:positiveq, r:ZH1:x = q * two_power_pos p + rH2:0 <= rH3:r < two_power_pos pZdiv_rest_proofs x p
Direct correctness of Zdiv_rest
x:Zp:positivelet (q, r) := Zdiv_rest x p in x = q * 2 ^ Z.pos p + r /\ 0 <= r < 2 ^ Z.pos px:Zp:positivelet (q, r) := Zdiv_rest x p in x = q * 2 ^ Z.pos p + r /\ 0 <= r < 2 ^ Z.pos px:Zp:positivelet (q, r) := let (qr, _) := Pos.iter Zdiv_rest_aux (x, 0, 1) p in qr in x = q * 2 ^ Z.pos p + r /\ 0 <= r < 2 ^ Z.pos px:Zp:positive(let '(q, r, d) := Pos.iter Zdiv_rest_aux (x, 0, 1) p in x = q * d + r /\ 0 <= r < d) -> (let (_, d) := Pos.iter Zdiv_rest_aux (x, 0, 1) p in d = two_power_pos p) -> let (q, r) := let (qr, _) := Pos.iter Zdiv_rest_aux (x, 0, 1) p in qr in x = q * 2 ^ Z.pos p + r /\ 0 <= r < 2 ^ Z.pos px:Zp:positiveq, r, d:Zx = q * d + r /\ 0 <= r < d -> d = two_power_pos p -> x = q * 2 ^ Z.pos p + r /\ 0 <= r < 2 ^ Z.pos pnow rewrite two_power_pos_equiv in H. Qed.x:Zp:positiveq, r:ZH:x = q * two_power_pos p + r /\ 0 <= r < two_power_pos px = q * 2 ^ Z.pos p + r /\ 0 <= r < 2 ^ Z.pos p
Equivalence with Z.shiftr
x:Zp:positivefst (Zdiv_rest x p) = Z.shiftr x (Z.pos p)x:Zp:positivefst (Zdiv_rest x p) = Z.shiftr x (Z.pos p)x:Zp:positive(let (q, r) := Zdiv_rest x p in x = q * 2 ^ Z.pos p + r /\ 0 <= r < 2 ^ Z.pos p) -> fst (Zdiv_rest x p) = Z.shiftr x (Z.pos p)x:Zp:positiveq, r:Zx = q * 2 ^ Z.pos p + r /\ 0 <= r < 2 ^ Z.pos p -> fst (q, r) = Z.shiftr x (Z.pos p)x:Zp:positiveq, r:ZH:x = q * 2 ^ Z.pos p + rH':0 <= r < 2 ^ Z.pos pfst (q, r) = Z.shiftr x (Z.pos p)x:Zp:positiveq, r:ZH:x = q * 2 ^ Z.pos p + rH':0 <= r < 2 ^ Z.pos pq = Z.shiftr x (Z.pos p)x:Zp:positiveq, r:ZH:x = q * 2 ^ Z.pos p + rH':0 <= r < 2 ^ Z.pos pq = x / 2 ^ Z.pos pnow rewrite Z.mul_comm. Qed. End power_div_with_rest.x:Zp:positiveq, r:ZH:x = q * 2 ^ Z.pos p + rH':0 <= r < 2 ^ Z.pos px = 2 ^ Z.pos p * q + r