Quotient and remainder #
There are three main conventions for integer division,
referred here as the E, F, T rounding conventions.
All three pairs satisfy the identity x % y + (x / y) * y = x
unconditionally,
and satisfy x / 0 = 0
and x % 0 = x
.
T-rounding division #
div
uses the ["T-rounding"][t-rounding]
(Truncation-rounding) convention, meaning that it rounds toward
zero. Also note that division by zero is defined to equal zero.
The relation between integer division and modulo is found in
Int.mod_add_div
which states that
a % b + b * (a / b) = a
, unconditionally.
[t-rounding]: https://dl.acm.org/doi/pdf/10.1145/128861.128862 [theo mod_add_div]: https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Int.mod_add_div#doc
Examples:
#eval (7 : Int).div (0 : Int) -- 0
#eval (0 : Int).div (7 : Int) -- 0
#eval (12 : Int).div (6 : Int) -- 2
#eval (12 : Int).div (-6 : Int) -- -2
#eval (-12 : Int).div (6 : Int) -- -2
#eval (-12 : Int).div (-6 : Int) -- 2
#eval (12 : Int).div (7 : Int) -- 1
#eval (12 : Int).div (-7 : Int) -- -1
#eval (-12 : Int).div (7 : Int) -- -1
#eval (-12 : Int).div (-7 : Int) -- 1
Implemented by efficient native code.
Equations
Instances For
Integer modulo. This function uses the
"T-rounding" (Truncation-rounding) convention
to pair with Int.div
, meaning that a % b + b * (a / b) = a
unconditionally (see Int.mod_add_div
). In
particular, a % 0 = a
.
Examples:
#eval (7 : Int).mod (0 : Int) -- 7
#eval (0 : Int).mod (7 : Int) -- 0
#eval (12 : Int).mod (6 : Int) -- 0
#eval (12 : Int).mod (-6 : Int) -- 0
#eval (-12 : Int).mod (6 : Int) -- 0
#eval (-12 : Int).mod (-6 : Int) -- 0
#eval (12 : Int).mod (7 : Int) -- 5
#eval (12 : Int).mod (-7 : Int) -- 5
#eval (-12 : Int).mod (7 : Int) -- -5
#eval (-12 : Int).mod (-7 : Int) -- -5
Implemented by efficient native code.
Equations
Instances For
Integer division. This version of division uses the F-rounding convention
(flooring division), in which Int.fdiv x y
satisfies fdiv x y = floor (x / y)
and Int.fmod
is the unique function satisfying fmod x y + (fdiv x y) * y = x
.
Examples:
#eval (7 : Int).fdiv (0 : Int) -- 0
#eval (0 : Int).fdiv (7 : Int) -- 0
#eval (12 : Int).fdiv (6 : Int) -- 2
#eval (12 : Int).fdiv (-6 : Int) -- -2
#eval (-12 : Int).fdiv (6 : Int) -- -2
#eval (-12 : Int).fdiv (-6 : Int) -- 2
#eval (12 : Int).fdiv (7 : Int) -- 1
#eval (12 : Int).fdiv (-7 : Int) -- -2
#eval (-12 : Int).fdiv (7 : Int) -- -2
#eval (-12 : Int).fdiv (-7 : Int) -- 1
Equations
- Int.fdiv 0 x = 0
- (Int.ofNat m).fdiv (Int.ofNat n) = Int.ofNat (m / n)
- (Int.ofNat m.succ).fdiv (Int.negSucc n) = Int.negSucc (m / n.succ)
- (Int.negSucc a).fdiv 0 = 0
- (Int.negSucc m).fdiv (Int.ofNat n.succ) = Int.negSucc (m / n.succ)
- (Int.negSucc m).fdiv (Int.negSucc n) = Int.ofNat (m.succ / n.succ)
Instances For
Integer modulus. This version of Int.mod
uses the F-rounding convention
(flooring division), in which Int.fdiv x y
satisfies fdiv x y = floor (x / y)
and Int.fmod
is the unique function satisfying fmod x y + (fdiv x y) * y = x
.
Examples:
#eval (7 : Int).fmod (0 : Int) -- 7
#eval (0 : Int).fmod (7 : Int) -- 0
#eval (12 : Int).fmod (6 : Int) -- 0
#eval (12 : Int).fmod (-6 : Int) -- 0
#eval (-12 : Int).fmod (6 : Int) -- 0
#eval (-12 : Int).fmod (-6 : Int) -- 0
#eval (12 : Int).fmod (7 : Int) -- 5
#eval (12 : Int).fmod (-7 : Int) -- -2
#eval (-12 : Int).fmod (7 : Int) -- 2
#eval (-12 : Int).fmod (-7 : Int) -- -5
Equations
- Int.fmod 0 x = 0
- (Int.ofNat m).fmod (Int.ofNat n) = Int.ofNat (m % n)
- (Int.ofNat m.succ).fmod (Int.negSucc n) = Int.subNatNat (m % n.succ) n
- (Int.negSucc m).fmod (Int.ofNat n) = Int.subNatNat n (m % n).succ
- (Int.negSucc m).fmod (Int.negSucc n) = -Int.ofNat (m.succ % n.succ)
Instances For
Integer division. This version of Int.div
uses the E-rounding convention
(euclidean division), in which Int.emod x y
satisfies 0 ≤ mod x y < natAbs y
for y ≠ 0
and Int.ediv
is the unique function satisfying emod x y + (ediv x y) * y = x
.
This is the function powering the /
notation on integers.
Examples:
#eval (7 : Int) / (0 : Int) -- 0
#eval (0 : Int) / (7 : Int) -- 0
#eval (12 : Int) / (6 : Int) -- 2
#eval (12 : Int) / (-6 : Int) -- -2
#eval (-12 : Int) / (6 : Int) -- -2
#eval (-12 : Int) / (-6 : Int) -- 2
#eval (12 : Int) / (7 : Int) -- 1
#eval (12 : Int) / (-7 : Int) -- -1
#eval (-12 : Int) / (7 : Int) -- -2
#eval (-12 : Int) / (-7 : Int) -- 2
Implemented by efficient native code.
Equations
- (Int.ofNat m).ediv (Int.ofNat n) = Int.ofNat (m / n)
- (Int.ofNat m).ediv (Int.negSucc n) = -Int.ofNat (m / n.succ)
- (Int.negSucc a).ediv 0 = 0
- (Int.negSucc m).ediv (Int.ofNat n.succ) = Int.negSucc (m / n.succ)
- (Int.negSucc m).ediv (Int.negSucc n) = Int.ofNat (m / n.succ).succ
Instances For
Integer modulus. This version of Int.mod
uses the E-rounding convention
(euclidean division), in which Int.emod x y
satisfies 0 ≤ emod x y < natAbs y
for y ≠ 0
and Int.ediv
is the unique function satisfying emod x y + (ediv x y) * y = x
.
This is the function powering the %
notation on integers.
Examples:
#eval (7 : Int) % (0 : Int) -- 7
#eval (0 : Int) % (7 : Int) -- 0
#eval (12 : Int) % (6 : Int) -- 0
#eval (12 : Int) % (-6 : Int) -- 0
#eval (-12 : Int) % (6 : Int) -- 0
#eval (-12 : Int) % (-6 : Int) -- 0
#eval (12 : Int) % (7 : Int) -- 5
#eval (12 : Int) % (-7 : Int) -- 5
#eval (-12 : Int) % (7 : Int) -- 2
#eval (-12 : Int) % (-7 : Int) -- 2
Implemented by efficient native code.
Equations
- (Int.ofNat m).emod x = Int.ofNat (m % x.natAbs)
- (Int.negSucc m).emod x = Int.subNatNat x.natAbs (m % x.natAbs).succ
Instances For
The Div and Mod syntax uses ediv and emod for compatibility with SMTLIb and mathematical reasoning tends to be easier.
Equations
- Int.instDiv = { div := Int.ediv }
bmod
("balanced" mod) #
Balanced mod (and balanced div) are a division and modulus pair such
that b * (Int.bdiv a b) + Int.bmod a b = a
and b/2 ≤ Int.bmod a b < b/2
for all a : Int
and b > 0
.
This is used in Omega as well as signed bitvectors.