(** Given a triple (mantissa, exponent, position), this function
    computes a triple with a canonic exponent, assuming the
    original triple had enough precision. *)

Definition truncate t :=
  let '(m, e, l) := t in
  let k := (fexp (Zdigits beta m + e) - e)%Z in
  if Zlt_bool 0 k then truncate_aux t k
  else t.

(* Specifications: *)
Theorem truncate_0 : forall e l, let '(m', e', l') := truncate (0, e, l)%Z in m' = Z0.
Theorem generic_format_truncate : forall m e l, (0 <= m)%Z -> let '(m', e', l') := truncate (m, e, l) in format (F2R (Float beta m' e')).
Theorem truncate_correct_format : forall m e, m <> Z0 -> let x := F2R (Float beta m e) in generic_format beta fexp x -> (e <= fexp (Zdigits beta m + e))%Z -> let '(m', e', l') := truncate (m, e, loc_Exact) in x = F2R (Float beta m' e') /\ e' = canonic_exp beta fexp x.
Theorem truncate_correct_partial : forall x m e l, (0 < x)%R -> inbetween_float beta m e x l -> (e <= fexp (Zdigits beta m + e))%Z -> let '(m', e', l') := truncate (m, e, l) in inbetween_float beta m' e' x l' /\ e' = canonic_exp beta fexp x.
Theorem truncate_correct : forall x m e l, (0 <= x)%R -> inbetween_float beta m e x l -> (e <= fexp (Zdigits beta m + e))%Z \/ l = loc_Exact -> let '(m', e', l') := truncate (m, e, l) in inbetween_float beta m' e' x l' /\ (e' = canonic_exp beta fexp x \/ (l' = loc_Exact /\ format x)).
Theorem round_any_correct : forall x m e l, inbetween_float beta m e x l -> (e = canonic_exp beta fexp x \/ (l = loc_Exact /\ format x)) -> round beta fexp rnd x = F2R (Float beta (choice m l) e).
Theorem round_trunc_any_correct : forall x m e l, (0 <= x)%R -> inbetween_float beta m e x l -> (e <= fexp (Zdigits beta m + e))%Z \/ l = loc_Exact -> round beta fexp rnd x = let '(m', e', l') := truncate (m, e, l) in F2R (Float beta (choice m' l') e').
Theorem round_sign_any_correct : forall x m e l, inbetween_float beta m e (Rabs x) l -> (e = canonic_exp beta fexp x \/ (l = loc_Exact /\ format x)) -> round beta fexp rnd x = F2R (Float beta (cond_Zopp (Rlt_bool x 0) (choice (Rlt_bool x 0) m l)) e).
Theorem round_trunc_sign_any_correct : forall x m e l, inbetween_float beta m e (Rabs x) l -> (e <= fexp (Zdigits beta m + e))%Z \/ l = loc_Exact -> round beta fexp rnd x = let '(m', e', l') := truncate (m, e, l) in F2R (Float beta (cond_Zopp (Rlt_bool x 0) (choice (Rlt_bool x 0) m' l')) e').
Theorem truncate_0 : forall e l, let '(m', e', l') := truncate (0, e, l)%Z in m' = Z0.
Theorem generic_format_truncate : forall m e l, (0 <= m)%Z -> let '(m', e', l') := truncate (m, e, l) in format (F2R (Float beta m' e')).
Theorem truncate_correct_format : forall m e, m <> Z0 -> let x := F2R (Float beta m e) in generic_format beta fexp x -> (e <= fexp (Zdigits beta m + e))%Z -> let '(m', e', l') := truncate (m, e, loc_Exact) in x = F2R (Float beta m' e') /\ e' = canonic_exp beta fexp x.
Theorem truncate_correct_partial : forall x m e l, (0 < x)%R -> inbetween_float beta m e x l -> (e <= fexp (Zdigits beta m + e))%Z -> let '(m', e', l') := truncate (m, e, l) in inbetween_float beta m' e' x l' /\ e' = canonic_exp beta fexp x.
Theorem truncate_correct : forall x m e l, (0 <= x)%R -> inbetween_float beta m e x l -> (e <= fexp (Zdigits beta m + e))%Z \/ l = loc_Exact -> let '(m', e', l') := truncate (m, e, l) in inbetween_float beta m' e' x l' /\ (e' = canonic_exp beta fexp x \/ (l' = loc_Exact /\ format x)).
Theorem round_any_correct : forall x m e l, inbetween_float beta m e x l -> (e = canonic_exp beta fexp x \/ (l = loc_Exact /\ format x)) -> round beta fexp rnd x = F2R (Float beta (choice m l) e).
Theorem round_trunc_any_correct : forall x m e l, (0 <= x)%R -> inbetween_float beta m e x l -> (e <= fexp (Zdigits beta m + e))%Z \/ l = loc_Exact -> round beta fexp rnd x = let '(m', e', l') := truncate (m, e, l) in F2R (Float beta (choice m' l') e').
Theorem round_sign_any_correct : forall x m e l, inbetween_float beta m e (Rabs x) l -> (e = canonic_exp beta fexp x \/ (l = loc_Exact /\ format x)) -> round beta fexp rnd x = F2R (Float beta (cond_Zopp (Rlt_bool x 0) (choice (Rlt_bool x 0) m l)) e).
Theorem round_trunc_sign_any_correct : forall x m e l, inbetween_float beta m e (Rabs x) l -> (e <= fexp (Zdigits beta m + e))%Z \/ l = loc_Exact -> round beta fexp rnd x = let '(m', e', l') := truncate (m, e, l) in F2R (Float beta (cond_Zopp (Rlt_bool x 0) (choice (Rlt_bool x 0) m' l')) e').