Library Coq.ZArith.BinIntDef
Binary Integers, Definitions of Operations
Initial author: Pierre Crégut, CNET, Lannion, France
Module Z.
Definition t :=
Z.
Nicer names Z.pos and Z.neg for contructors
Definition zero := 0.
Definition one := 1.
Definition two := 2.
Subtraction of positive into Z
Fixpoint pos_sub (
x y:
positive) {
struct y} :
Z :=
match x,
y with
|
p~1,
q~1 =>
double (
pos_sub p q)
|
p~1,
q~0 =>
succ_double (
pos_sub p q)
|
p~1, 1 =>
pos p~0
|
p~0,
q~1 =>
pred_double (
pos_sub p q)
|
p~0,
q~0 =>
double (
pos_sub p q)
|
p~0, 1 =>
pos (
Pos.pred_double p)
| 1,
q~1 =>
neg q~0
| 1,
q~0 =>
neg (
Pos.pred_double q)
| 1, 1 =>
Z0
end%
positive.
Definition add x y :=
match x,
y with
| 0,
y =>
y
|
x, 0 =>
x
|
pos x´,
pos y´ =>
pos (
x´ + y´)
|
pos x´,
neg y´ =>
pos_sub x´ y´
|
neg x´,
pos y´ =>
pos_sub y´ x´
|
neg x´,
neg y´ =>
neg (
x´ + y´)
end.
Infix "+" :=
add :
Z_scope.
Definition opp x :=
match x with
| 0 => 0
|
pos x =>
neg x
|
neg x =>
pos x
end.
Notation "- x" := (
opp x) :
Z_scope.
Definition sub m n :=
m + -n.
Infix "-" :=
sub :
Z_scope.
Definition mul x y :=
match x,
y with
| 0,
_ => 0
|
_, 0 => 0
|
pos x´,
pos y´ =>
pos (
x´ * y´)
|
pos x´,
neg y´ =>
neg (
x´ * y´)
|
neg x´,
pos y´ =>
neg (
x´ * y´)
|
neg x´,
neg y´ =>
pos (
x´ * y´)
end.
Infix "*" :=
mul :
Z_scope.
Definition compare x y :=
match x,
y with
| 0, 0 =>
Eq
| 0,
pos y´ =>
Lt
| 0,
neg y´ =>
Gt
|
pos x´, 0 =>
Gt
|
pos x´,
pos y´ => (
x´ ?= y´)%
positive
|
pos x´,
neg y´ =>
Gt
|
neg x´, 0 =>
Lt
|
neg x´,
pos y´ =>
Lt
|
neg x´,
neg y´ =>
CompOpp ((
x´ ?= y´)%
positive)
end.
Infix "?=" :=
compare (
at level 70,
no associativity) :
Z_scope.
Definition sgn z :=
match z with
| 0 => 0
|
pos p => 1
|
neg p => -1
end.
Boolean equality and comparisons
Nota: geb and gtb are provided for compatibility,
but leb and ltb should rather be used instead, since
more results will be available on them.
Definition geb x y :=
match x ?= y with
|
Lt =>
false
|
_ =>
true
end.
Definition gtb x y :=
match x ?= y with
|
Gt =>
true
|
_ =>
false
end.
Fixpoint eqb x y :=
match x,
y with
| 0, 0 =>
true
|
pos p,
pos q =>
Pos.eqb p q
|
neg p,
neg q =>
Pos.eqb p q
|
_,
_ =>
false
end.
Infix "=?" :=
eqb (
at level 70,
no associativity) :
Z_scope.
Infix "<=?" :=
leb (
at level 70,
no associativity) :
Z_scope.
Infix "<?" :=
ltb (
at level 70,
no associativity) :
Z_scope.
Infix ">=?" :=
geb (
at level 70,
no associativity) :
Z_scope.
Infix ">?" :=
gtb (
at level 70,
no associativity) :
Z_scope.
Definition abs z :=
match z with
| 0 => 0
|
pos p =>
pos p
|
neg p =>
pos p
end.
Conversions
From
Z to
nat via absolute value
From Z to N via absolute value
Definition abs_N (
z:
Z) :
N :=
match z with
| 0 => 0%
N
|
pos p =>
N.pos p
|
neg p =>
N.pos p
end.
From Z to nat by rounding negative numbers to 0
From Z to N by rounding negative numbers to 0
Definition to_N (
z:
Z) :
N :=
match z with
|
pos p =>
N.pos p
|
_ => 0%
N
end.
From nat to Z
From N to Z
Definition of_N (
n:
N) :
Z :=
match n with
| 0%
N => 0
|
N.pos p =>
pos p
end.
From Z to positive by rounding nonpositive numbers to 1
Definition to_pos (
z:
Z) :
positive :=
match z with
|
pos p =>
p
|
_ => 1%
positive
end.
Iteration of a function
By convention, iterating a negative number of times is identity.
Euclidean divisions for binary integers
Concerning the many possible variants of integer divisions,
see the headers of the generic files
ZDivFloor,
ZDivTrunc,
ZDivEucl, and the article by R. Boute mentioned there.
We provide here two flavours, Floor and Trunc, while
the Euclid convention can be found in file Zeuclid.v
For non-zero b, they all satisfy
a = b*(a/b) + (a mod b)
and
|a mod b| < |b| , but the sign of the modulo will differ
when
a<0 and/or
b<0.
Floor division
div_eucl provides a Truncated-Toward-Bottom (a.k.a Floor)
Euclidean division. Its projections are named
div (noted "/")
and
modulo (noted with an infix "mod").
These functions correspond to the `div` and `mod` of Haskell.
This is the historical convention of Coq.
The main properties of this convention are :
- we have sgn (a mod b) = sgn (b)
- div a b is the greatest integer smaller or equal to the exact
fraction a/b.
- there is no easy sign rule.
In addition, note that we arbitrary take
a/0 = 0 and
a mod 0 = 0.
First, a division for positive numbers. Even if the second
argument is a Z, the answer is arbitrary is it isn't a Zpos.
Then the general euclidean division
Definition div_eucl (
a b:
Z) :
Z * Z :=
match a,
b with
| 0,
_ =>
(0
, 0
)
|
_, 0 =>
(0
, 0
)
|
pos a´,
pos _ =>
pos_div_eucl a´ b
|
neg a´,
pos _ =>
let (
q,
r) :=
pos_div_eucl a´ b in
match r with
| 0 =>
(- q, 0
)
|
_ =>
(- (q + 1
), b - r)
end
|
neg a´,
neg b´ =>
let (
q,
r) :=
pos_div_eucl a´ (
pos b´)
in (q, - r)
|
pos a´,
neg b´ =>
let (
q,
r) :=
pos_div_eucl a´ (
pos b´)
in
match r with
| 0 =>
(- q, 0
)
|
_ =>
(- (q + 1
), b + r)
end
end.
Definition div (
a b:
Z) :
Z :=
let (
q,
_) :=
div_eucl a b in q.
Definition modulo (
a b:
Z) :
Z :=
let (
_,
r) :=
div_eucl a b in r.
Infix "/" :=
div :
Z_scope.
Infix "mod" :=
modulo (
at level 40,
no associativity) :
Z_scope.
Trunc Division
quotrem provides a Truncated-Toward-Zero Euclidean division.
Its projections are named
quot (noted "÷") and
rem.
These functions correspond to the `quot` and `rem` of Haskell.
This division convention is used in most programming languages,
e.g. Ocaml.
With this convention:
- we have sgn(a rem b) = sgn(a)
- sign rule for division: quot (-a) b = quot a (-b) = -(quot a b)
- and for modulo: a rem (-b) = a rem b and (-a) rem b = -(a rem b)
Note that we arbitrary take here
quot a 0 = 0 and
a rem 0 = a.
Definition quotrem (
a b:
Z) :
Z * Z :=
match a,
b with
| 0,
_ =>
(0
, 0
)
|
_, 0 =>
(0
, a)
|
pos a,
pos b =>
let (
q,
r) :=
N.pos_div_eucl a (
N.pos b)
in (of_N q, of_N r)
|
neg a,
pos b =>
let (
q,
r) :=
N.pos_div_eucl a (
N.pos b)
in (-of_N q, - of_N r)
|
pos a,
neg b =>
let (
q,
r) :=
N.pos_div_eucl a (
N.pos b)
in (-of_N q, of_N r)
|
neg a,
neg b =>
let (
q,
r) :=
N.pos_div_eucl a (
N.pos b)
in (of_N q, - of_N r)
end.
Definition quot a b :=
fst (
quotrem a b).
Definition rem a b :=
snd (
quotrem a b).
Infix "÷" :=
quot (
at level 40,
left associativity) :
Z_scope.
No infix notation for rem, otherwise it becomes a keyword
Parity functions
Division by two
div2 performs rounding toward bottom, it is hence a particular
case of
div, and for all relative number
n we have:
n = 2 * div2 n + if odd n then 1 else 0.
quot2 performs rounding toward zero, it is hence a particular
case of quot, and for all relative number n we have:
n = 2 * quot2 n + if odd n then sgn n else 0.
NB:
Z.quot2 used to be named
Z.div2 in Coq <= 8.3
Base-2 logarithm
A generalized gcd, also computing division of a and b by gcd.
Definition ggcd a b :
Z*(Z*Z) :=
match a,
b with
| 0,
_ =>
(abs b,(0
, sgn b))
|
_, 0 =>
(abs a,(sgn a, 0
))
|
pos a,
pos b =>
let ´
(g,(aa,bb)) :=
Pos.ggcd a b in (pos g, (pos aa, pos bb))
|
pos a,
neg b =>
let ´
(g,(aa,bb)) :=
Pos.ggcd a b in (pos g, (pos aa, neg bb))
|
neg a,
pos b =>
let ´
(g,(aa,bb)) :=
Pos.ggcd a b in (pos g, (neg aa, pos bb))
|
neg a,
neg b =>
let ´
(g,(aa,bb)) :=
Pos.ggcd a b in (pos g, (neg aa, neg bb))
end.
Bitwise functions
When accessing the bits of negative numbers, all functions
below will use the two's complement representation. For instance,
-1 will correspond to an infinite stream of true bits. If this
isn't what you're looking for, you can use
abs first and then
access the bits of the absolute value.
testbit : accessing the
n-th bit of a number
a.
For negative
n, we arbitrarily answer
false.
Shifts
Nota: a shift to the right by
-n will be a shift to the left
by
n, and vice-versa.
For fulfilling the two's complement convention, shifting to
the right a negative number should correspond to a division
by 2 with rounding toward bottom, hence the use of
div2
instead of
quot2.
Bitwise operations lor land ldiff lxor
Definition lor a b :=
match a,
b with
| 0,
_ =>
b
|
_, 0 =>
a
|
pos a,
pos b =>
pos (
Pos.lor a b)
|
neg a,
pos b =>
neg (
N.succ_pos (
N.ldiff (
Pos.pred_N a) (
N.pos b)))
|
pos a,
neg b =>
neg (
N.succ_pos (
N.ldiff (
Pos.pred_N b) (
N.pos a)))
|
neg a,
neg b =>
neg (
N.succ_pos (
N.land (
Pos.pred_N a) (
Pos.pred_N b)))
end.
Definition land a b :=
match a,
b with
| 0,
_ => 0
|
_, 0 => 0
|
pos a,
pos b =>
of_N (
Pos.land a b)
|
neg a,
pos b =>
of_N (
N.ldiff (
N.pos b) (
Pos.pred_N a))
|
pos a,
neg b =>
of_N (
N.ldiff (
N.pos a) (
Pos.pred_N b))
|
neg a,
neg b =>
neg (
N.succ_pos (
N.lor (
Pos.pred_N a) (
Pos.pred_N b)))
end.
Definition ldiff a b :=
match a,
b with
| 0,
_ => 0
|
_, 0 =>
a
|
pos a,
pos b =>
of_N (
Pos.ldiff a b)
|
neg a,
pos b =>
neg (
N.succ_pos (
N.lor (
Pos.pred_N a) (
N.pos b)))
|
pos a,
neg b =>
of_N (
N.land (
N.pos a) (
Pos.pred_N b))
|
neg a,
neg b =>
of_N (
N.ldiff (
Pos.pred_N b) (
Pos.pred_N a))
end.
Definition lxor a b :=
match a,
b with
| 0,
_ =>
b
|
_, 0 =>
a
|
pos a,
pos b =>
of_N (
Pos.lxor a b)
|
neg a,
pos b =>
neg (
N.succ_pos (
N.lxor (
Pos.pred_N a) (
N.pos b)))
|
pos a,
neg b =>
neg (
N.succ_pos (
N.lxor (
N.pos a) (
Pos.pred_N b)))
|
neg a,
neg b =>
of_N (
N.lxor (
Pos.pred_N a) (
Pos.pred_N b))
end.
End Z.