(************************************************************************)
(*         *      The Rocq Prover / The Rocq Development Team           *)
(*  v      *         Copyright INRIA, CNRS and contributors             *)
(* <O___,, * (see version control and CREDITS file for authors & dates) *)
(*   \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)         *)
(************************************************************************)
(** * Uint63 numbers defines indeed a cyclic structure : Z/(2^63)Z *)
(** Author: Arnaud Spiwack (+ Pierre Letouzey) *)
Require Export ZArith.
Require Export Uint63.
Local Open Scope uint63_scope.
(** {2 Operators } **)
Definition Pdigits := Eval compute in P_of_succ_nat (size - 1).
Fixpoint positive_to_int_rec (n:nat) (p:positive) :=
match n, p with
| O, _ => (Npos p, 0)
| S n, xH => (0%N, 1)
| S n, xO p =>
let (N,i) := positive_to_int_rec n p in
(N, i << 1)
| S n, xI p =>
let (N,i) := positive_to_int_rec n p in
(N, (i << 1) + 1)
end.
Definition positive_to_int := positive_to_int_rec size.
Definition mulc_WW x y :=
let (h, l) := mulc x y in
if is_zero h then
if is_zero l then W0
else WW h l
else WW h l.
Notation "n '*c' m" := (mulc_WW n m) (at level 40, no associativity) : uint63_scope.
Definition pos_mod p x :=
if p <=? digits then
let p := digits - p in
(x << p) >> p
else x.
Notation pos_mod_int := pos_mod.
#[global]
Instance int_ops : ZnZ.Ops int :=
{|
digits      := Pdigits; (* number of digits *)
zdigits     := Uint63Axioms.digits; (* number of digits *)
to_Z        := Uint63Axioms.to_Z; (* conversion to Z *)
of_pos      := positive_to_int; (* positive -> N*int63 :  p => N,i
where p = N*2^31+phi i *)
head0       := Uint63.head0;  (* number of head 0 *)
tail0       := Uint63.tail0;  (* number of tail 0 *)
zero        := 0;
one         := 1;
minus_one   := Uint63Axioms.max_int;
compare     := Uint63.compare;
eq0         := Uint63Axioms.is_zero;
opp_c       := Uint63.oppc;
opp         := Uint63.opp;
opp_carry   := Uint63.oppcarry;
succ_c      := Uint63.succc;
add_c       := Uint63.addc;
add_carry_c := Uint63.addcarryc;
succ        := Uint63.succ;
add         := Uint63.add;
add_carry   := Uint63Axioms.addcarry;
pred_c      := Uint63.predc;
sub_c       := Uint63.subc;
sub_carry_c := Uint63.subcarryc;
pred        := Uint63.pred;
sub         := Uint63.sub;
sub_carry   := Uint63.subcarry;
mul_c       := mulc_WW;
mul         := Uint63.mul;
square_c    := fun x => mulc_WW x x;
div21       := diveucl_21;
div_gt      := diveucl; (* this is supposed to be the special case of
division a/b where a > b *)
div         := diveucl;
modulo_gt   := Uint63.mod;
modulo      := Uint63.mod;
gcd_gt      := Uint63.gcd;
gcd         := Uint63.gcd;
add_mul_div := Uint63.addmuldiv;
pos_mod     := pos_mod_int;
is_even     := Uint63Axioms.is_even;
sqrt2       := Uint63.sqrt2;
sqrt        := Uint63.sqrt;
ZnZ.lor     := Uint63.lor;
ZnZ.land    := Uint63.land;
ZnZ.lxor    := Uint63.lxor
|}.
Local Open Scope Z_scope.

Lemma mulc_WW_spec :
forall x y, Φ ( x *c y ) = φ x * φ y.