1
------------------------------------------------------------------------
2
-- Digits and digit expansions
3
------------------------------------------------------------------------
5
module Data.Digit where
8
open import Data.Nat.Properties
10
open import Data.Fin as Fin using (Fin; zero; suc; toℕ)
11
open import Relation.Nullary.Decidable
12
open import Data.Char using (Char)
14
open import Data.Vec as Vec using (Vec; _∷_; [])
15
open import Induction.Nat
16
open import Data.Nat.DivMod
18
open import Relation.Binary.PropositionalEquality
19
open import Data.Function
21
------------------------------------------------------------------------
26
lem : ∀ x k r → 2 + x ≤′ r + (1 + x) * (2 + k)
27
lem x k r = ≤⇒≤′ $ begin
30
2 + x + (x + (1 + x) * k + r)
31
≡⟨ solve 3 (λ x r k → con 2 :+ x :+ (x :+ (con 1 :+ x) :* k :+ r)
33
r :+ (con 1 :+ x) :* (con 2 :+ k))
38
------------------------------------------------------------------------
41
-- Digit b is the type of digits in base b.
46
-- Some specific digit kinds.
59
------------------------------------------------------------------------
62
-- The characters used to show the first 16 digits.
64
digitChars : Vec Char 16
66
'0' ∷ '1' ∷ '2' ∷ '3' ∷ '4' ∷ '5' ∷ '6' ∷ '7' ∷ '8' ∷ '9' ∷
67
'a' ∷ 'b' ∷ 'c' ∷ 'd' ∷ 'e' ∷ 'f' ∷ []
69
-- showDigit shows digits in base ≤ 16.
71
showDigit : ∀ {base} {base≤16 : True (base ≤? 16)} →
73
showDigit {base≤16 = base≤16} d =
74
Vec.lookup (Fin.inject≤ d (toWitness base≤16)) digitChars
76
------------------------------------------------------------------------
79
-- fromDigits takes a digit expansion of a natural number, starting
80
-- with the _least_ significant digit, and returns the corresponding
83
fromDigits : ∀ {base} → List (Fin base) → ℕ
85
fromDigits {base} (d ∷ ds) = toℕ d + fromDigits ds * base
87
-- toDigits b n yields the digits of n, in base b, starting with the
88
-- _least_ significant digit.
90
-- Note that the list of digits is always non-empty.
92
-- This function should be linear in n, if optimised properly (see
95
data Digits (base : ℕ) : ℕ → Set where
96
digits : (ds : List (Fin base)) → Digits base (fromDigits ds)
98
toDigits : (base : ℕ) {base≥2 : True (2 ≤? base)} (n : ℕ) →
100
toDigits zero {base≥2 = ()} _
101
toDigits (suc zero) {base≥2 = ()} _
102
toDigits (suc (suc k)) n = <-rec Pred helper n
107
cons : ∀ {n} (r : Fin base) → Pred n → Pred (toℕ r + n * base)
108
cons r (digits ds) = digits (r ∷ ds)
110
helper : ∀ n → <-Rec Pred n → Pred n
111
helper n rec with n divMod base
112
helper .(toℕ r + 0 * base) rec | result zero r = digits (r ∷ [])
113
helper .(toℕ r + suc x * base) rec | result (suc x) r =
114
cons r (rec (suc x) (lem (pred (suc x)) k (toℕ r)))
116
theDigits : (base : ℕ) {base≥2 : True (2 ≤? base)} (n : ℕ) →
118
theDigits base {base≥2} n with toDigits base {base≥2} n
119
theDigits base .(fromDigits ds) | digits ds = ds