(************************************************************************)
(*         *      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)         *)
(************************************************************************)
(** * DecimalFacts : some facts about Decimal numbers *)
Variant digits := d0 | d1 | d2 | d3 | d4 | d5 | d6 | d7 | d8 | d9.
Fixpoint to_list (u : uint) : list digits :=
match u with
| Nil => nil
| D0 u => cons d0 (to_list u)
| D1 u => cons d1 (to_list u)
| D2 u => cons d2 (to_list u)
| D3 u => cons d3 (to_list u)
| D4 u => cons d4 (to_list u)
| D5 u => cons d5 (to_list u)
| D6 u => cons d6 (to_list u)
| D7 u => cons d7 (to_list u)
| D8 u => cons d8 (to_list u)
| D9 u => cons d9 (to_list u)
end.
Fixpoint of_list (l : list digits) : uint :=
match l with
| nil => Nil
| cons d0 l => D0 (of_list l)
| cons d1 l => D1 (of_list l)
| cons d2 l => D2 (of_list l)
| cons d3 l => D3 (of_list l)
| cons d4 l => D4 (of_list l)
| cons d5 l => D5 (of_list l)
| cons d6 l => D6 (of_list l)
| cons d7 l => D7 (of_list l)
| cons d8 l => D8 (of_list l)
| cons d9 l => D9 (of_list l)
end.

(* Specifications: *)
Lemma of_list_to_list u : of_list (to_list u) = u.
Lemma of_list_inj u u' : of_list u = of_list u' -> u = u'.
Lemma nb_digits_spec u : nb_digits u = length (to_list u).
Definition lnztail l :=
let fix aux l_rev :=
match l_rev with
| cons d0 l_rev => let (r, n) := aux l_rev in pair r (S n)
| _ => pair l_rev O
end in
let (r, n) := aux (List.rev l) in pair (List.rev r) n.
Lemma nztail_spec d :
let (r, n) := nztail d in
let (r', n') := lnztail (to_list d) in
to_list r = r' /\ n = n'.
Lemma del_head_spec_0 d : del_head 0 d = d.
Lemma del_head_spec_large n d : length (to_list d) < n -> del_head n d = zero.
Lemma nb_digits_0 d : nb_digits d = 0 -> d = Nil.
Lemma nb_digits_n0 d : nb_digits d <> 0 -> d <> Nil.
Lemma nb_digits_rev d : nb_digits (rev d) = nb_digits d.
Lemma unorm_D0 u : unorm (D0 u) = unorm u.
Lemma iter_D0_unorm d :
d <> Nil ->
Nat.iter (nb_digits d - nb_digits (unorm d)) D0 (unorm d) = d.
Lemma nzhead_app_l d d' :
nb_digits d' < nb_digits (nzhead (app d d')) ->
nzhead (app d d') = app (nzhead d) d'.
Lemma nzhead_app_r d d' :
nb_digits (nzhead (app d d')) <= nb_digits d' ->
nzhead (app d d') = nzhead d'.
Lemma nzhead_app_nil_r d d' : nzhead (app d d') = Nil -> nzhead d' = Nil.
Lemma nzhead_app_nil d d' :
nb_digits (nzhead (app d d')) <= nb_digits d' -> nzhead d = Nil.
Lemma nzhead_app_nil_l d d' : nzhead (app d d') = Nil -> nzhead d = Nil.
Lemma unorm_app_zero d d' :
nb_digits (unorm (app d d')) <= nb_digits d' -> unorm d = zero.
Lemma app_int_nil_r d : app_int d Nil = d.
Lemma unorm_app_l d d' :
nb_digits d' < nb_digits (unorm (app d d')) ->
unorm (app d d') = app (unorm d) d'.
Lemma unorm_app_r d d' :
nb_digits (unorm (app d d')) <= nb_digits d' ->
unorm (app d d') = unorm d'.
Lemma norm_app_int d d' :
nb_digits d' < nb_digits (unorm (app (abs d) d')) ->
norm (app_int d d') = app_int (norm d) d'.
Lemma del_head_nb_digits d : del_head (nb_digits d) d = Nil.
Lemma del_tail_nb_digits d : del_tail (nb_digits d) d = Nil.
Lemma del_tail_app n d d' :
n <= nb_digits d' -> del_tail n (app d d') = app d (del_tail n d').
Lemma del_tail_app_int n d d' :
n <= nb_digits d' -> del_tail_int n (app_int d d') = app_int d (del_tail n d').
Lemma app_int_del_tail_head n (d:int) :
n <= nb_digits (abs d) ->
app_int (del_tail_int n d) (del_head (nb_digits (abs d) - n) (abs d)) = d.
Lemma del_tail_app_int_exact i f :
nb_digits f < nb_digits (unorm (app (abs i) f)) ->
del_tail_int (nb_digits f) (norm (app_int i f)) = norm i.