203 lines
6 KiB
Text
203 lines
6 KiB
Text
/-
|
|
Copyright (c) 2016 Jeremy Avigad. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
Authors: Jeremy Avigad, Mario Carneiro
|
|
-/
|
|
prelude
|
|
import Init.Data.Int.Basic
|
|
|
|
open Nat
|
|
|
|
namespace Int
|
|
|
|
/-! ## 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]
|
|
(**T**runcation-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) / (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) -- -1
|
|
#eval (-12 : Int) / (-7 : Int) -- 1
|
|
```
|
|
|
|
Implemented by efficient native code.
|
|
-/
|
|
@[extern "lean_int_div"]
|
|
def div : (@& Int) → (@& Int) → Int
|
|
| ofNat m, ofNat n => ofNat (m / n)
|
|
| ofNat m, -[n +1] => -ofNat (m / succ n)
|
|
| -[m +1], ofNat n => -ofNat (succ m / n)
|
|
| -[m +1], -[n +1] => ofNat (succ m / succ n)
|
|
|
|
/-- Integer modulo. This function uses the
|
|
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention
|
|
to pair with `Int.div`, meaning that `a % b + b * (a / b) = a`
|
|
unconditionally (see [`Int.mod_add_div`][theo mod_add_div]). In
|
|
particular, `a % 0 = a`.
|
|
|
|
[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) % (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. -/
|
|
@[extern "lean_int_mod"]
|
|
def mod : (@& Int) → (@& Int) → Int
|
|
| ofNat m, ofNat n => ofNat (m % n)
|
|
| ofNat m, -[n +1] => ofNat (m % succ n)
|
|
| -[m +1], ofNat n => -ofNat (succ m % n)
|
|
| -[m +1], -[n +1] => -ofNat (succ m % succ n)
|
|
|
|
/-! ### F-rounding division
|
|
This pair satisfies `fdiv x y = floor (x / y)`.
|
|
-/
|
|
|
|
/--
|
|
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`.
|
|
-/
|
|
def fdiv : Int → Int → Int
|
|
| 0, _ => 0
|
|
| ofNat m, ofNat n => ofNat (m / n)
|
|
| ofNat (succ m), -[n+1] => -[m / succ n +1]
|
|
| -[_+1], 0 => 0
|
|
| -[m+1], ofNat (succ n) => -[m / succ n +1]
|
|
| -[m+1], -[n+1] => ofNat (succ m / succ n)
|
|
|
|
/--
|
|
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`.
|
|
-/
|
|
def fmod : Int → Int → Int
|
|
| 0, _ => 0
|
|
| ofNat m, ofNat n => ofNat (m % n)
|
|
| ofNat (succ m), -[n+1] => subNatNat (m % succ n) n
|
|
| -[m+1], ofNat n => subNatNat n (succ (m % n))
|
|
| -[m+1], -[n+1] => -ofNat (succ m % succ n)
|
|
|
|
/-! ### E-rounding division
|
|
This pair satisfies `0 ≤ mod x y < natAbs y` for `y ≠ 0`.
|
|
-/
|
|
|
|
/--
|
|
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`.
|
|
-/
|
|
@[extern "lean_int_ediv"]
|
|
def ediv : (@& Int) → (@& Int) → Int
|
|
| ofNat m, ofNat n => ofNat (m / n)
|
|
| ofNat m, -[n+1] => -ofNat (m / succ n)
|
|
| -[_+1], 0 => 0
|
|
| -[m+1], ofNat (succ n) => -[m / succ n +1]
|
|
| -[m+1], -[n+1] => ofNat (succ (m / succ n))
|
|
|
|
/--
|
|
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`.
|
|
-/
|
|
@[extern "lean_int_emod"]
|
|
def emod : (@& Int) → (@& Int) → Int
|
|
| ofNat m, n => ofNat (m % natAbs n)
|
|
| -[m+1], n => subNatNat (natAbs n) (succ (m % natAbs n))
|
|
|
|
/--
|
|
The Div and Mod syntax uses ediv and emod for compatibility with SMTLIb and mathematical
|
|
reasoning tends to be easier.
|
|
-/
|
|
instance : Div Int where
|
|
div := Int.ediv
|
|
instance : Mod Int where
|
|
mod := Int.emod
|
|
|
|
@[simp, norm_cast] theorem ofNat_ediv (m n : Nat) : (↑(m / n) : Int) = ↑m / ↑n := rfl
|
|
|
|
/-!
|
|
# `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.
|
|
-/
|
|
|
|
/--
|
|
Balanced modulus. This version of Integer modulus uses the
|
|
balanced rounding convention, which guarantees that
|
|
`m/2 ≤ bmod x m < m/2` for `m ≠ 0` and `bmod x m` is congruent
|
|
to `x` modulo `m`.
|
|
|
|
If `m = 0`, then `bmod x m = x`.
|
|
-/
|
|
def bmod (x : Int) (m : Nat) : Int :=
|
|
let r := x % m
|
|
if r < (m + 1) / 2 then
|
|
r
|
|
else
|
|
r - m
|
|
|
|
/--
|
|
Balanced division. This returns the unique integer so that
|
|
`b * (Int.bdiv a b) + Int.bmod a b = a`.
|
|
-/
|
|
def bdiv (x : Int) (m : Nat) : Int :=
|
|
if m = 0 then
|
|
0
|
|
else
|
|
let q := x / m
|
|
let r := x % m
|
|
if r < (m + 1) / 2 then
|
|
q
|
|
else
|
|
q + 1
|
|
|
|
end Int
|