(********************************************************************)
(*                                                                  *)
(*  The Why3 Verification Platform   /   The Why3 Development Team  *)
(*  Copyright 2010-2024 --  Inria - CNRS - Paris-Saclay University  *)
(*                                                                  *)
(*  This software is distributed under the terms of the GNU Lesser  *)
(*  General Public License version 2.1, with the special exception  *)
(*  on linking described in file LICENSE.                           *)
(*                                                                  *)
(********************************************************************)

(* This file is generated by Why3's Coq-realize driver *)
(* Beware! Only edit allowed sections below    *)
Require Import BuiltIn.
Require Reals.Rbasic_fun.
Require Reals.R_sqrt.
Require BuiltIn.
Require int.Int.
Require real.Real.
Require real.RealInfix.
Require real.Abs.
Require real.FromInt.
Require real.Truncate.
Require real.Square.
Require bv.Pow2int.
Require ieee_float.RoundingMode.

Require Import Psatz.
Require Import ZArith Reals.
Require Import Flocq.Core.Core.
Require Import Flocq.IEEE754.BinarySingleNaN.
Require Import Flocq.Calc.Bracket.
Require Import Flocq.Calc.Round.
Require Import Flocq.Prop.Plus_error.
Require Flocq.Prop.Sterbenz.
Import real.Truncate.
Import ieee_float.RoundingMode.

Arguments B754_zero {prec} {emax}.
Arguments B754_infinity {prec} {emax}.
Arguments B754_nan {prec} {emax}.
Arguments B754_finite {prec} {emax}.

Local Open Scope R_scope.

Definition mode_to_IEEE : mode -> BinarySingleNaN.mode.
  exact (fun m =>
           match m with
           | RNE => mode_NE
           | RNA => mode_NA
           | RTP => mode_UP
           | RTN => mode_DN
           | RTZ => mode_ZR
           end).
Defined.

Coercion mode_to_IEEE : mode >-> BinarySingleNaN.mode.

Section GenericFloat.

Variable eb_pos sb_pos : positive.

(* Why3 goal *)
Definition eb : Numbers.BinNums.Z.
Proof.
  exact (Z.pos eb_pos).
Defined.

(* Why3 goal *)
Definition sb : Numbers.BinNums.Z.
Proof.
  exact (Z.pos sb_pos).
Defined.

Hypothesis Heb : Zlt_bool 1 eb = true.
Hypothesis Hsbb : Zlt_bool 1 sb = true.

(* Why3 goal *)
Lemma eb_gt_1 : (1%Z < eb)%Z.
Proof.
  rewrite Zlt_is_lt_bool.
  apply Heb.
Qed.

(* Why3 goal *)
Lemma sb_gt_1 : (1%Z < sb)%Z.
Proof.
  rewrite Zlt_is_lt_bool.
  apply Hsbb.
Qed.

(* power of infinities *)
Definition emax : Z.
Proof.
  exact (radix2 ^ (eb - 1))%Z.
Defined.

(* Why3 goal *)
Definition t : Type.
Proof.
  exact (binary_float sb emax).
Defined.

(* Why3 goal *)
Definition zeroF : t.
Proof.
  exact (B754_zero false).
Defined.

Definition emin := (3 - emax - sb)%Z.
Notation fexp := (FLT_exp emin sb).

Lemma Hsb : Zlt_bool 0 sb = true.
Proof.
  auto with zarith.
Qed.

Lemma Hsb': (0 < sb)%Z.
Proof.
  unfold sb; auto with zarith.
Qed.

Hypothesis Hemax : Zlt_bool sb emax = true.

Lemma Hemax': (sb < emax)%Z.
Proof.
  rewrite Zlt_is_lt_bool.
  apply Hemax.
Qed.

Instance Hsb'' : Prec_gt_0 sb := Hsb'.

Lemma fexp_Valid : Valid_exp fexp.
Proof.
  apply (fexp_correct _ _ Hsb'').
Qed.

Definition r_to_fp rnd x : binary_float sb emax :=
  let r := round radix2 fexp (round_mode rnd) x in
  let m := Ztrunc (scaled_mantissa radix2 fexp r) in
  let e := cexp radix2 fexp r in
  binary_normalize sb emax Hsb' Hemax' rnd m e false.

Theorem r_to_fp_correct :
  forall rnd x,
  let r := round radix2 fexp (round_mode rnd) x in
  (Rabs r < bpow radix2 emax)%R ->
  is_finite (r_to_fp rnd x) = true /\
  B2R (r_to_fp rnd x) = r.
Proof with auto with typeclass_instances.
intros rnd x r Bx.
unfold r_to_fp. fold r.
generalize (binary_normalize_correct sb emax Hsb' Hemax' rnd (Ztrunc (scaled_mantissa radix2 fexp r)) (cexp radix2 fexp r) false).
unfold r.
elim generic_format_round...
fold emin r.
rewrite round_generic...
rewrite Rlt_bool_true with (1 := Bx).
now split.
apply generic_format_round...
Qed.

Theorem r_to_fp_format :
  forall rnd x,
  FLT_format radix2 emin sb x ->
  (Rabs x < bpow radix2 emax)%R ->
  B2R (r_to_fp rnd x) = x.
Proof with auto with typeclass_instances.
intros rnd x Fx Bx.
assert (Gx: generic_format radix2 fexp x).
apply generic_format_FLT.
apply Fx.
pattern x at 2 ; rewrite <- round_generic with (rnd := round_mode rnd) (2 := Gx)...
refine (proj2 (r_to_fp_correct _ _ _)).
rewrite round_generic...
Qed.

Lemma max_eb_bounded : SpecFloat.bounded sb emax (2 ^ sb_pos - 1) (emax - sb) = true.
Proof.
  assert (0 <= sb - 1)%Z.
  apply Zlt_0_le_0_pred, Hsb'.
  unfold SpecFloat.bounded; apply Bool.andb_true_iff; split.
  unfold SpecFloat.canonical_mantissa, SpecFloat.fexp, FLT_exp, SpecFloat.emin.
  apply Zeq_bool_true.
  rewrite Digits.Zpos_digits2_pos.
  rewrite (Digits.Zdigits_unique radix2 _ sb).
  assert (sb + (emax - sb) - sb = emax - sb)%Z by ring; rewrite H0.
  apply Zmax_left.
  assert (1 < emax)%Z.
  apply Z.le_lt_trans with (m := sb).
  change (Z.succ 0 <= sb)%Z; apply Zgt_le_succ; easy.
  apply Hemax'.
  auto with zarith.
  rewrite Z.abs_eq by auto with zarith.
  change ((2 ^ (sb - 1) <= Z.pos (2 ^ sb_pos - 1) < 2 ^ sb)%Z).
  assert (Z.pos (2 ^ sb_pos - 1) = 2 ^ sb -1)%Z.
  rewrite Pos2Z.inj_sub, Pos2Z.inj_pow.
  fold sb; reflexivity.
  apply Pos.pow_gt_1; easy.
  rewrite H0.
  split; auto with zarith.
  assert (sb = Z.succ (sb - 1)) by auto with zarith.
  rewrite H1 at 2.
  rewrite Z.pow_succ_r by trivial.
  assert (1 <= 2 ^ (sb - 1))%Z.
  apply Z.lt_pred_le, (Zpower_gt_0 radix2 (sb - 1)); trivial.
  lia.
  apply Zle_bool_true; auto with zarith.
Qed.

Definition max_value: t.
Proof.
  exact (B754_finite false (2 ^ sb_pos - 1) (emax - sb) max_eb_bounded).
Defined.

(* Why3 goal *)
Definition add : ieee_float.RoundingMode.mode -> t -> t -> t.
Proof.
  exact (@Bplus sb emax Hsb' Hemax').
Defined.

(* Why3 goal *)
Definition sub : ieee_float.RoundingMode.mode -> t -> t -> t.
Proof.
  exact (@Bminus sb emax Hsb' Hemax').
Defined.

(* Why3 goal *)
Definition mul : ieee_float.RoundingMode.mode -> t -> t -> t.
Proof.
  exact (@Bmult sb emax Hsb' Hemax').
Defined.

(* Why3 goal *)
Definition div : ieee_float.RoundingMode.mode -> t -> t -> t.
Proof.
  exact (@Bdiv sb emax Hsb' Hemax').
Defined.

(* Why3 goal *)
Definition abs : t -> t.
Proof.
  exact (@Babs sb emax).
Defined.

(* Why3 goal *)
Definition neg : t -> t.
Proof.
  exact (@Bopp sb emax).
Defined.

(* Why3 goal *)
Definition fma : ieee_float.RoundingMode.mode -> t -> t -> t -> t.
Proof.
  exact (@Bfma sb emax Hsb' Hemax').
Defined.

(* Why3 goal *)
Definition sqrt : ieee_float.RoundingMode.mode -> t -> t.
Proof.
  exact (@Bsqrt sb emax Hsb' Hemax').
Defined.

Definition z_to_fp m x := binary_normalize sb emax Hsb' Hemax' (mode_to_IEEE m) x 0 false.

Definition fp_to_z: mode -> t -> Z.
Proof.
  exact (fun m x => match m with
         | RNA => ZnearestA
         | RNE => ZnearestE
         | RTP => Zceil
         | RTN => Zfloor
         | RTZ => Ztrunc
         end (B2R x)).
Defined.

(* Why3 goal *)
Definition roundToIntegral : ieee_float.RoundingMode.mode -> t -> t.
Proof.
  exact (fun m x =>
           match x with
             | B754_zero b => x
             | B754_infinity b => x
             | B754_nan => x
             | B754_finite b ma e _ =>
               let x_int := fp_to_z m x in
               match Z.eq_dec x_int 0%Z with
               | left _ => B754_zero b
               | right _ => z_to_fp RTZ x_int
               end
           end).
Defined.

(* Why3 goal *)
Definition min : t -> t -> t.
Proof.
  exact (fun x y => match Bcompare x y with
           | Some Lt => x
           | Some Gt | Some Eq => y
           | None => B754_nan
         end).
Defined.

(* Why3 goal *)
Definition max : t -> t -> t.
Proof.
  exact (fun x y => match Bcompare x y with
           | Some Lt => y
           | Some Gt | Some Eq => x
           | None => B754_nan
         end).
Defined.

(* Why3 goal *)
Definition le : t -> t -> Prop.
Proof.
  exact (fun a b => match Bcompare a b with Some Lt | Some Eq => True | _ => False end).
Defined.

Hint Unfold le.

(* Why3 goal *)
Definition lt : t -> t -> Prop.
Proof.
  exact (fun a b => Bcompare a b = Some Lt).
Defined.

Hint Unfold lt.

Lemma gt_bcompare : forall {x y}, lt y x <-> Bcompare x y = Some Gt.
Proof.
  intros x y.
  rewrite Bcompare_swap.
  unfold lt.
  destruct Bcompare.
  destruct c; simpl; split; intro h; inversion h; auto.
  split; intro h; inversion h; auto.
Qed.

(*
Lemma ge_bcompare : forall {x y}, le y x <-> Bcompare _ _ x y = Some Gt \/ Bcompare _ _ x y = Some Eq.
Proof.
  intros x y.
  unfold le.
  rewrite <-gt_bcompare.
  assert (Bcompare _ _ y x = Some Eq <-> Bcompare _ _ x y = Some Eq).
  rewrite Bcompare_swap.
  destruct Bcompare; try (split; now auto).
  destruct c; simpl; split; intro h; inversion h; auto.
  rewrite H; reflexivity.
Qed.
*)

(* Why3 goal *)
Definition eq : t -> t -> Prop.
Proof.
  exact (fun a b => Bcompare a b = Some Eq).
Defined.

Hint Unfold eq.

Lemma le_correct: forall x y, le x y <-> lt x y \/ eq x y.
Proof.
  intros x y; unfold lt, le, eq.
  destruct Bcompare as [[ | | ] | ] ; split ; try easy.
  now right.
  now left.
  now intros [|].
  now intros [|].
Qed.

Lemma lt_le: forall {x y}, lt x y -> le x y.
Proof.
  intros x y.
  rewrite le_correct; auto.
Qed.

Lemma eq_zero_iff: forall {x}, eq zeroF x <-> x = zeroF \/ x = neg zeroF.
Proof.
  intro; unfold eq; destruct x; simpl; try destruct s; simpl.
  split; auto.
  split; auto.
  split; [easy| intro h; destruct h; easy].
  split; [easy| intro h; destruct h; easy].
  split; [easy| intro h; destruct h; easy].
  split; [easy| intro h; destruct h; easy].
  split; [easy| intro h; destruct h; easy].
Qed.

(* Why3 goal *)
Definition is_normal : t -> Prop.
Proof.
  exact (fun x => match x with
                    | B754_zero _ => True
                    | B754_finite _ _ e _ => (emin < e)%Z
                    | _ => False
        end).
Defined.

(* Why3 goal *)
Definition is_subnormal : t -> Prop.
Proof.
  exact (fun x => match x with
                    | B754_finite _ _ e _ => (emin = e)%Z
                    | _ => False
        end).
Defined.

(* Why3 goal *)
Definition is_zero : t -> Prop.
Proof.
  exact (fun x => eq zeroF x).
Defined.

Lemma zero_is_zero: forall {b}, is_zero (B754_zero b).
Proof.
  easy.
Qed.

Lemma is_zero_B754_zero :
  forall x, is_zero x <-> exists b, x = B754_zero b.
Proof.
  intro.
  unfold is_zero; rewrite eq_zero_iff.
  unfold zeroF.
  simpl neg.
  split; intro h; destruct h; auto; try easy.
  exists false; assumption.
  exists true; assumption.
  destruct x0;[right|left];auto.
Qed.

Lemma zero_or_not : forall x, ~ is_zero x \/ is_zero x.
Proof.
  destruct x.
  - now right.
  - left. now destruct s.
  - now left.
  - left. now destruct s.
Qed.

(* Why3 goal *)
Definition is_infinite : t -> Prop.
Proof.
  exact (fun x => match x with
                  | B754_infinity _ => True
                  | _ => False
                  end).
Defined.

Coercion is_true : bool >-> Sortclass.

Lemma eq_infinite_dist: forall {x y}, eq x y -> is_infinite x -> is_infinite y.
Proof.
  intros; destruct x, y; try easy; destruct s; easy.
Qed.

(* Why3 goal *)
Definition is_nan : t -> Prop.
Proof.
  exact is_nan.
Defined.

Lemma is_infinite_not_nan: forall {x}, is_infinite x -> ~ is_nan x.
Proof.
  intro x; destruct x; easy.
Qed.

Lemma le_infinity: forall {x}, ~ is_nan x -> le x (B754_infinity false).
Proof.
  intros.
  unfold le.
  destruct x; try easy.
  + now destruct s.
  + now elim H.
Qed.

Lemma is_nan_dec: forall x, {is_nan x} + {~ is_nan x}.
Proof.
  intro; destruct x; compute; intuition.
Qed.

Lemma eq_not_nan_refl: forall {x : t}, ~ is_nan x -> eq x x.
Proof.
  intros; destruct x; auto.
  destruct s; auto.
  destruct H; easy.
  unfold eq.
  rewrite Bcompare_correct by easy.
  now rewrite Rcompare_Eq.
Qed.

Lemma eq_not_nan: forall {x y}, eq x y -> ~ is_nan x /\ ~ is_nan y.
Proof.
  intros; destruct x; destruct y; easy.
Qed.

Lemma lt_not_nan: forall {x y}, lt x y -> ~ is_nan x /\ ~ is_nan y.
Proof.
  intros; destruct x, y; easy.
Qed.

Lemma le_or_lt_or_nan: forall x y, le x y \/ lt y x \/ is_nan x \/ is_nan y.
Proof.
  unfold is_nan, le, lt.
  intros x y.
  rewrite Bcompare_swap.
  case_eq (Bcompare y x).
  intros [| |] ; try now left.
  now (right ; left).
  destruct x, y; auto; easy.
Qed.

(* Why3 goal *)
Definition is_positive : t -> Prop.
Proof.
  exact (fun x => match x with
                    | B754_zero false => True
                    | B754_finite false _ e _ => True
                    | B754_infinity false => True
                    | _ => False
        end).
Defined.

Hint Unfold is_positive.

Lemma is_positive_Bsign: forall x, ~ is_nan x -> (is_positive x <-> Bsign x = false).
Proof.
  split.
  destruct x; try destruct s; try easy.
  destruct x; try destruct s; try easy.
  contradict H; easy.
Qed.

Lemma is_positive_correct: forall x, is_positive x <-> lt zeroF x \/ x = B754_zero false.
Proof.
  split.
  intro h; destruct x; try destruct s; auto; easy.
  intro h; destruct h; destruct x; try destruct s; easy.
Qed.

(* Why3 goal *)
Definition is_negative : t -> Prop.
Proof.
  exact (fun x => match x with
                    | B754_zero true => True
                    | B754_finite true _ e _ => True
                    | B754_infinity true => True
                    | _ => False
        end).
Defined.

Hint Unfold is_negative.

Lemma is_negative_Bsign: forall x, ~ is_nan x -> (is_negative x <-> Bsign x = true).
Proof.
  split.
  destruct x; try destruct s; easy.
  destruct x; try destruct s; easy.
Qed.

Lemma is_negative_correct: forall x, is_negative x <-> lt x zeroF \/ x = B754_zero true.
Proof.
  split.
  intro h; destruct x; try destruct s; auto; easy.
  intro h; destruct h; destruct x; try destruct s; easy.
Qed.

(* Why3 goal *)
Definition is_finite : t -> Prop.
Proof.
  exact is_finite.
Defined.

Lemma not_nan: forall x, ~ (is_nan x) -> {is_finite x} + {is_infinite x}.
Proof.
  unfold is_nan, is_finite.
  intro x; try destruct x; simpl; intro; auto.
Qed.

Lemma is_finite_not_nan: forall {x}, is_finite x -> ~ is_nan x.
Proof.
  intro x; destruct x; easy.
Qed.

Lemma Finite_Infinite_Nan_dec: forall x:t, {is_finite x} + {is_infinite x} + {is_nan x}.
Proof.
  intro x; destruct x; simpl.
  left; left; easy.
  left; right; easy.
  right; easy.
  left; left; easy.
Qed.

Lemma eq_finite_dist: forall {x y}, eq x y -> is_finite x -> is_finite y.
Proof.
  intros; destruct x, y; try easy; destruct s0; easy.
Qed.

Lemma bounded_floats :
  forall x:t, (is_finite x) ->
              Bcompare (abs x) max_value = Some Lt
           \/ Bcompare (abs x) max_value = Some Eq.
Proof.
  destruct x; try easy; auto; (* simpl; *) intros.
  destruct (andb_prop _ _ e0) as (H1,H2).
  generalize (Zeq_bool_eq _ _ H1); clear H1; intro H1.
  generalize (Zle_bool_imp_le _ _ H2); clear H2; intro H2.
  destruct (Z_le_lt_eq_dec _ _ H2); clear H2.
  unfold Bcompare.
  simpl; rewrite (Zcompare_Lt _ _ l); auto.
  unfold Bcompare.
  simpl; rewrite (Zcompare_Eq _ _ e1).
  unfold SpecFloat.fexp, FLT_exp, SpecFloat.emin in H1.
  rewrite Digits.Zpos_digits2_pos in H1.
  assert (3 - emax - sb <= Digits.Zdigits radix2 (Z.pos m) + e - sb)%Z.
  rewrite e1.
  pose sb_gt_1. pose Hemax'.
  assert (Z.pos m <> 0)%Z. pose (Pos2Z.is_pos m); auto with zarith.
  pose (Digits.Zdigits_gt_0 radix2 (Z.pos m) H0).
  auto with zarith.
  rewrite <-Z.max_l_iff in H0.
  rewrite H0 in H1; clear H0.
  assert (Digits.Zdigits radix2 (Z.pos m) = sb) by auto with zarith; clear H1.
  pose (Digits.Zdigits_correct radix2 (Z.pos m)).
  rewrite H0 in a.
  replace (Z.abs (Z.pos m)) with (Z.pos m) in a by auto with zarith.
  destruct a. clear H1.
  assert (Z.pos m = radix2 ^ sb - 1 \/ Z.pos m < radix2 ^ sb - 1)%Z by lia.
  destruct H1.
  right.
  replace (radix2 ^ sb)%Z with (Z.pos 2 ^ Z.pos sb_pos)%Z in H1 by auto.
  rewrite <-Pos2Z.inj_pow, <-Pos2Z.inj_sub, <-Zpos_eq_iff in H1.
  rewrite H1.
  rewrite Pcompare_refl; reflexivity.
  apply Pos.pow_gt_1; easy.
  left.
  rewrite nat_of_P_lt_Lt_compare_complement_morphism. reflexivity.
  apply Pos2Nat.inj_lt.
  replace (radix2 ^ sb)%Z with (Z.pos 2 ^ Z.pos sb_pos)%Z in H1 by auto.
  rewrite <-Pos2Z.inj_pow, <-Pos2Z.inj_sub in H1.
  auto with zarith.
  apply Pos.pow_gt_1; easy.
Qed.

Lemma bounded_floats_le: forall x, is_finite x -> le (abs x) max_value.
Proof.
  intros x Fx.
  unfold le.
  now destruct (bounded_floats x Fx) as [-> | ->].
Qed.

Lemma is_finite_B: forall (x:t),
    is_finite x ->
    exists b, x = B754_zero b \/ exists b m e p, x = B754_finite b m e p.
Proof.
  intro x.
  destruct x; try easy; intros.
  exists s; auto.
  exists s; right.
  exists s, m, e, e0; trivial.
Qed.

(* Why3 assumption *)
Definition is_plus_infinity (x:t) : Prop := is_infinite x /\ is_positive x.

(* Why3 assumption *)
Definition is_minus_infinity (x:t) : Prop := is_infinite x /\ is_negative x.

(* Why3 assumption *)
Definition is_plus_zero (x:t) : Prop := is_zero x /\ is_positive x.

(* Why3 assumption *)
Definition is_minus_zero (x:t) : Prop := is_zero x /\ is_negative x.

(* Why3 assumption *)
Definition is_not_nan (x:t) : Prop := is_finite x \/ is_infinite x.

(* Why3 goal *)
Lemma is_not_nan1 : forall (x:t), is_not_nan x <-> ~ is_nan x.
Proof.
  unfold is_not_nan; split; intro H.
  destruct H; [apply is_finite_not_nan|apply is_infinite_not_nan];trivial.
  destruct (not_nan _ H); auto.
Qed.

(* Why3 goal *)
Lemma is_not_finite :
  forall (x:t), ~ is_finite x <-> is_infinite x \/ is_nan x.
Proof.
intros x.
destruct x; split; intro h; try easy.
contradict h; easy.
destruct h as [h|h]; contradict h; easy.
left; easy.
right; easy.
contradict h; easy.
destruct h as [h|h]; contradict h; easy.
Qed.

(* Why3 goal *)
Definition to_real : t -> Reals.Rdefinitions.R.
Proof.
  exact B2R.
Defined.

Lemma Some_ext: forall {T} (a b:T), Some a = Some b <-> a = b.
Proof.
  intros; split; intro H;[inversion H|rewrite H]; reflexivity.
Qed.

Lemma to_real_eq: forall {x:t} {y:t}, is_finite x -> is_finite y ->
                                      (eq x y <-> to_real x = to_real y).
Proof.
  intros x y h1 h2.
  unfold eq.
  rewrite (Bcompare_correct _ _ x y h1 h2), Some_ext.
  split; intro H; [apply (Rcompare_Eq_inv _ _ H)|
                   apply (Rcompare_Eq _ _ H)].
Qed.

Lemma to_real_eq_alt: forall {x y}, eq x y -> to_real x = to_real y.
Proof.
  destruct x, y; try destruct s; try destruct s0; unfold eq, Bcompare; simpl; try easy.
  - destruct (Z_dec e e1) as [[s|s]|s].
    + rewrite Zcompare_Lt by auto; intro; easy.
    + apply Z.gt_lt in s.
      rewrite Zcompare_Gt by auto; intro; easy.
    + rewrite Zcompare_Eq by auto; intro.
      inversion H.
      rewrite <-ZC4 in H1.
      apply Pcompare_Eq_eq in H1.
      destruct m; simpl; subst; auto.
  - destruct (Z_dec e e1) as [[s|s]|s].
    + rewrite Zcompare_Lt by auto; intro; easy.
    + apply Z.gt_lt in s.
      rewrite Zcompare_Gt by auto; intro; easy.
    + rewrite Zcompare_Eq by auto; intro.
      inversion H.
      apply Pcompare_Eq_eq in H1.
      destruct m; simpl; subst; auto.
Qed.

Lemma le_to_real: forall (x:t) (y:t), is_finite x -> is_finite y ->
  (le x y <-> (to_real x <= to_real y)%R).
Proof.
intros x y h1 h2.
unfold le.
rewrite (Bcompare_correct _ _ x y h1 h2).
split; intro H.
- apply Rnot_lt_le.
  intros H'.
  now rewrite Rcompare_Gt in H.
- case Rcompare_spec; try easy.
  now apply Rle_not_lt.
Qed.

(* Why3 goal *)
Lemma zeroF_is_positive : is_positive zeroF.
Proof.
easy.
Qed.

(* Why3 goal *)
Lemma zeroF_is_zero : is_zero zeroF.
Proof.
  apply eq_refl; easy.
Qed.

Lemma zeroF_to_real : ((to_real zeroF) = 0%R).
Proof.
easy.
Qed.

Lemma B754_zero_to_real: forall {b}, to_real (B754_zero b) = 0%R.
Proof.
  intro b.
  rewrite <-(to_real_eq_alt zero_is_zero).
  apply zeroF_to_real.
Qed.

(* Why3 goal *)
Lemma zero_to_real :
  forall (x:t), is_zero x <-> is_finite x /\ ((to_real x) = 0%R).
Proof.
  unfold is_zero.
  assert (is_finite zeroF) by easy.
  intros x; split; intro H0.
  assert (is_finite x) by apply (eq_finite_dist H0 H).
  split; auto.
  symmetry.
  rewrite <-(to_real_eq H H1); auto.
  destruct H0.
  rewrite to_real_eq; auto.
Qed.

(* Why3 goal *)
Notation of_int := z_to_fp.

(* Why3 goal *)
Notation to_int := fp_to_z.

Lemma to_int_zeroF: forall m, to_int m zeroF = 0%Z.
Proof.
  intro m.
  destruct (valid_rnd_round_mode m) as (_,b).
  pose proof (b 0%Z) as H; simpl in H.
  destruct m; simpl; auto.
Qed.

(* add to theory ? *)
Lemma to_int_eq: forall {m x y}, eq x y -> to_int m x = to_int m y.
Proof.
  destruct x, y; try destruct s; try destruct s0; unfold eq, Bcompare; simpl; try easy.
  - destruct (Z_dec e e1) as [[s|s]|s].
    + rewrite Zcompare_Lt by auto; intro; easy.
    + apply Z.gt_lt in s.
      rewrite Zcompare_Gt by auto; intro; easy.
    + rewrite Zcompare_Eq by auto; intro.
      inversion H.
      rewrite <-ZC4 in H1.
      apply Pcompare_Eq_eq in H1.
      destruct m; simpl; subst; auto.
  - destruct (Z_dec e e1) as [[s|s]|s].
    + rewrite Zcompare_Lt by auto; intro; easy.
    + apply Z.gt_lt in s.
      rewrite Zcompare_Gt by auto; intro; easy.
    + rewrite Zcompare_Eq by auto; intro.
      inversion H.
      apply Pcompare_Eq_eq in H1.
      destruct m; simpl; subst; auto.
Qed.

Lemma to_int_B754_zero: forall {b m}, to_int m (B754_zero b) = 0%Z.
Proof.
  intros b m.
  rewrite <-(to_int_eq zero_is_zero).
  apply to_int_zeroF.
Qed.

(* add to theory ? *)
Lemma to_int_le: forall {x y m}, is_finite x -> is_finite y -> le x y -> (to_int m x <= to_int m y)%Z.
Proof.
  intros.
  destruct m;

  [destruct (valid_rnd_round_mode mode_NE)|
   destruct (valid_rnd_NA)|
   destruct (valid_rnd_UP)|
   destruct (valid_rnd_DN)|
   destruct (valid_rnd_ZR)];
  apply Zrnd_le;
  apply le_to_real; auto.
Qed.

(* Why3 goal *)
Lemma zero_of_int :
  forall (m:ieee_float.RoundingMode.mode), (zeroF = (of_int m 0%Z)).
Proof.
auto.
Qed.

(* Why3 goal *)
Definition round :
  ieee_float.RoundingMode.mode -> Reals.Rdefinitions.R ->
  Reals.Rdefinitions.R.
Proof.
  exact (fun m => round radix2 fexp (round_mode m)).
Defined.

(* Why3 goal *)
Definition max_real : Reals.Rdefinitions.R.
Proof.
  exact ((1 - bpow radix2 (- sb)) * bpow radix2 emax)%R.
Defined.

Lemma max_real_is_F2R: @F2R radix2 {| Fnum := Z.pos (2 ^ sb_pos - 1); Fexp := emax - sb |} = max_real.
Proof.
  unfold F2R.
  unfold Fnum, Fexp.
  rewrite Pos2Z.inj_sub, Pos2Z.inj_pow, minus_IZR.
  fold sb.
  change 2%Z with (radix_val radix2).
  rewrite IZR_Zpower by easy.
  rewrite Int.infix_mn'def, bpow_plus.
  rewrite Rmult_comm, Rmult_assoc, Rmult_comm, Rmult_minus_distr_l.
  rewrite <-bpow_plus.
  replace (- sb + sb)%Z with 0%Z by auto with zarith.
  rewrite Rmult_1_r.
  reflexivity.
  apply Pos.pow_gt_1; easy.
Qed.

Lemma min_real_is_F2R: @F2R radix2 {| Fnum := Z.neg (2 ^ sb_pos - 1); Fexp := emax - sb |} = Ropp max_real.
Proof.
  rewrite <-max_real_is_F2R.
  rewrite <- Operations.F2R_opp.
  unfold Operations.Fopp.
  reflexivity.
Qed.

Lemma max_value_to_real: to_real max_value = max_real.
Proof.
  unfold B2R; simpl.
  apply max_real_is_F2R.
Qed.

Lemma max_real_alt : (max_real = bpow radix2 emax - bpow radix2 (emax - sb))%R.
Proof.
  unfold max_real.
  rewrite Rmult_minus_distr_r, Rmult_1_l.
  rewrite <-bpow_plus.
  replace (- sb + emax)%Z with (emax - sb)%Z by auto with zarith.
  reflexivity.
Qed.

Lemma max_real_lt_bpow_radix2_emax : (max_real < bpow radix2 emax)%R.
Proof.
  rewrite max_real_alt.
  generalize (bpow_gt_0 radix2 (emax - sb)).
  lra.
Qed.

Lemma max_real_ge_6 : (6 <= max_real)%R.
Proof.
  rewrite max_real_alt.
  assert (2 <= sb)%Z by (pose proof sb_gt_1; auto with zarith).
  assert (sb + 1 <= emax)%Z by (pose proof Hemax'; auto with zarith).
  assert (8 <= bpow radix2 emax)%R.
    apply (bpow_le radix2 3).
    lia.
  unfold Zminus.
  rewrite bpow_plus.
  assert (bpow radix2 emax * bpow radix2 (-sb) <= bpow radix2 emax * / 4)%R.
    apply Rmult_le_compat_l.
    apply bpow_ge_0.
    apply (bpow_le radix2 _ (-2)).
    now apply Z.opp_le_mono.
  lra.
Qed.

Lemma max_real_generic_format: generic_format radix2 fexp max_real.
Proof.
  rewrite <-max_value_to_real.
  apply generic_format_B2R.
Qed.

(* Why3 goal *)
Definition max_int : Numbers.BinNums.Z.
Proof.
  exact (2 ^ emax - 2 ^ (emax - sb))%Z.
Defined.

(* Why3 goal *)
Lemma max_int_spec :
  (max_int =
   ((bv.Pow2int.pow2 (bv.Pow2int.pow2 (eb - 1%Z)%Z)) -
    (bv.Pow2int.pow2 ((bv.Pow2int.pow2 (eb - 1%Z)%Z) - sb)%Z))%Z).
Proof.
  rewrite two_p_equiv, two_p_equiv, two_p_equiv.
  now unfold max_int, emax.
Qed.

(* Why3 goal *)
Lemma max_real_int : (max_real = (BuiltIn.IZR max_int)).
Proof.
  unfold max_int.
  rewrite minus_IZR.
  change 2%Z with (radix_val radix2).
  rewrite IZR_Zpower, IZR_Zpower by (pose Hsb'; pose Hemax'; auto with zarith).
  apply max_real_alt.
Qed.

(* Why3 assumption *)
Definition in_range (x:Reals.Rdefinitions.R) : Prop :=
  ((-max_real)%R <= x)%R /\ (x <= max_real)%R.

(* Why3 assumption *)
Definition in_int_range (i:Numbers.BinNums.Z) : Prop :=
  ((-max_int)%Z <= i)%Z /\ (i <= max_int)%Z.

Lemma in_range_bpow_radix2_emax: forall x, in_range x -> (Rabs x < bpow radix2 emax)%R.
Proof.
  unfold in_range; intros.
  apply Rle_lt_trans with (r2:= max_real).
  apply Abs.Abs_le; apply H.
  apply max_real_lt_bpow_radix2_emax.
Qed.

Lemma is_finite_abs : forall x:t, is_finite x -> is_finite (abs x).
Proof.
  destruct x; try easy.
Qed.

(* Why3 goal *)
Lemma is_finite1 : forall (x:t), is_finite x -> in_range (to_real x).
Proof.
  intros x h1.
  apply Rabs_le_inv.
  rewrite <-max_value_to_real.
  apply Rcompare_not_Lt_inv.
  pose (is_finite_abs x h1).
  pose (bounded_floats x h1).
  rewrite Bcompare_correct in o; try easy.
  unfold abs in o.
  rewrite B2R_Babs in o.
  unfold to_real.
  intro H0.
  destruct o as [H|H]; inversion H as (H1);
  rewrite Rcompare_sym in H1; apply CompOpp_iff in H1;
  simpl in H0; rewrite H0 in H1;
  inversion H1.
Qed.

Lemma Rabs_round_max_real_emax:
  forall {m} {x}, Rabs (round m x) <= max_real <-> Rabs (round m x) < bpow radix2 emax.
Proof.
  intros m x; split; intro h.
  - apply Rle_lt_trans with (r2 := max_real).
    apply h.
    apply max_real_lt_bpow_radix2_emax.
  - destruct (r_to_fp_correct m x h).
    unfold round.
    rewrite <-H0, Abs.Abs_le.
    apply (is_finite1 _ H).
Qed.

(* Why3 assumption *)
Definition no_overflow (m:ieee_float.RoundingMode.mode)
    (x:Reals.Rdefinitions.R) : Prop :=
  in_range (round m x).

Lemma no_overflow_Rabs_round_max_real: forall {m} {x}, no_overflow m x <-> Rabs (round m x) <= max_real.
Proof.
  intro x.
  split; intro h; apply Abs.Abs_le; easy.
Qed.

Lemma no_overflow_Rabs_round_emax: forall {m} {x}, no_overflow m x <-> Rabs (round m x) < bpow radix2 emax.
Proof.
  intros m x.
  apply (iff_trans no_overflow_Rabs_round_max_real Rabs_round_max_real_emax).
Qed.

Lemma IZR_alt: forall {x}, @F2R radix2 {| Fnum := x; Fexp := 0 |} = IZR x.
Proof.
  intros; unfold F2R, Fnum, Fexp, FLT_exp.
  assert (bpow radix2 0 = 1) as bpow_0 by easy.
  rewrite bpow_0, Rmult_1_r.
  reflexivity.
Qed.

Lemma of_int_correct :
  forall {m} {x},
    no_overflow m (IZR x) ->
      to_real (of_int m x) = round m (IZR x) /\ is_finite (of_int m x) /\
      Bsign (of_int m x) =
      match (x ?= 0)%Z with
      | Eq => false
      | Lt => true
      | Gt => false
      end.
Proof.
  intros m x h1.
  generalize (binary_normalize_correct sb emax Hsb' Hemax' m x 0 false).
  simpl.
  rewrite Rlt_bool_true.
  - intro; destruct H; destruct H0.
    rewrite IZR_alt in H1.
    split.
    rewrite IZR_alt in H; auto.
    split; auto.
    rewrite <- Rcompare_IZR.
    exact H1.

  - apply no_overflow_Rabs_round_emax.
    rewrite IZR_alt; apply h1.
Qed.

(* Why3 goal *)
Lemma Bounded_real_no_overflow :
  forall (m:ieee_float.RoundingMode.mode) (x:Reals.Rdefinitions.R),
  in_range x -> no_overflow m x.
Proof.
intros m x h1.
rewrite no_overflow_Rabs_round_max_real.
apply abs_round_le_generic.
apply fexp_Valid.
apply valid_rnd_round_mode.
apply max_real_generic_format.
rewrite Abs.Abs_le; easy.
Qed.

(* Why3 goal *)
Lemma Round_monotonic :
  forall (m:ieee_float.RoundingMode.mode) (x:Reals.Rdefinitions.R)
    (y:Reals.Rdefinitions.R),
  (x <= y)%R -> ((round m x) <= (round m y))%R.
Proof.
  intros m x y h1.
  apply round_le.
  apply fexp_Valid.
  apply valid_rnd_round_mode.
  apply h1.
Qed.

Lemma round_lt : forall {x y} {m:mode}, round m x < round m y -> x < y.
Proof.
  intros x y m h.
  case (Rlt_dec x y); auto.
  intro.
  apply Rnot_lt_le in n.
  apply (Round_monotonic m) in n.
  apply RIneq.Rle_not_lt in n.
  contradict h; assumption.
Qed.

(* Why3 goal *)
Lemma Round_idempotent :
  forall (m1:ieee_float.RoundingMode.mode) (m2:ieee_float.RoundingMode.mode)
    (x:Reals.Rdefinitions.R),
  ((round m1 (round m2 x)) = (round m2 x)).
Proof with auto with typeclass_instances.
intros m1 m2 x.
apply round_generic...
apply generic_format_round...
Qed.

(* Why3 goal *)
Lemma Round_to_real :
  forall (m:ieee_float.RoundingMode.mode) (x:t), is_finite x ->
  ((round m (to_real x)) = (to_real x)).
Proof with auto with typeclass_instances.
intros m x h.
apply round_generic...
apply generic_format_B2R.
Qed.

(* Why3 goal *)
Lemma Round_down_le :
  forall (x:Reals.Rdefinitions.R),
  ((round ieee_float.RoundingMode.RTN x) <= x)%R.
Proof with auto with typeclass_instances.
intros x.
apply round_DN_pt...
Qed.

(* Why3 goal *)
Lemma Round_up_ge :
  forall (x:Reals.Rdefinitions.R),
  (x <= (round ieee_float.RoundingMode.RTP x))%R.
Proof with auto with typeclass_instances.
intros x.
apply round_UP_pt...
Qed.

(* Why3 goal *)
Lemma Round_down_neg :
  forall (x:Reals.Rdefinitions.R),
  ((round ieee_float.RoundingMode.RTN (-x)%R) =
   (-(round ieee_float.RoundingMode.RTP x))%R).
Proof.
intros x.
apply round_opp.
Qed.

(* Why3 goal *)
Lemma Round_up_neg :
  forall (x:Reals.Rdefinitions.R),
  ((round ieee_float.RoundingMode.RTP (-x)%R) =
   (-(round ieee_float.RoundingMode.RTN x))%R).
Proof.
intros x.
pattern x at 2 ; rewrite <- Ropp_involutive.
rewrite Round_down_neg.
now rewrite Ropp_involutive.
Qed.

(* Why3 goal *)
Definition pow2sb : Numbers.BinNums.Z.
Proof.
  exact (Zpower 2 sb).
Defined.

(* Why3 goal *)
Lemma pow2sb1 : (pow2sb = (bv.Pow2int.pow2 sb)).
Proof.
  now rewrite two_p_equiv.
Qed.

(* Why3 assumption *)
Definition in_safe_int_range (i:Numbers.BinNums.Z) : Prop :=
  ((-pow2sb)%Z <= i)%Z /\ (i <= pow2sb)%Z.

Lemma max_rep_int_bounded: SpecFloat.bounded sb emax (shift_pos (sb_pos - 1) 1) 1 = true.
Proof.
  unfold SpecFloat.bounded.
  apply Bool.andb_true_iff; split.
  unfold SpecFloat.canonical_mantissa.
  apply Zeq_bool_true.
  rewrite Digits.Zpos_digits2_pos, shift_pos_correct.
  rewrite Zmult_1_r, Z.pow_pos_fold.
  rewrite Digits.Zdigits_Zpower by easy.
  rewrite Pos2Z.inj_sub by exact sb_gt_1.
  fold sb.
  unfold SpecFloat.fexp, FLT_exp, SpecFloat.emin.
  replace (sb - 1 + 1 + 1 - sb)%Z with 1%Z by ring.
  apply Z.max_l.
  pose sb_gt_1; pose Hemax'; lia.
  apply Zle_bool_true.
  pose Hemax'; pose Hsbb; lia.
Qed.

Definition Bmax_rep_int: t.
Proof.
  exact (B754_finite false _ _ max_rep_int_bounded).
Defined.

Lemma IZR_pow2sb: IZR pow2sb = bpow radix2 sb.
Proof.
  easy.
Qed.

Lemma Bmax_rep_int_to_real: to_real Bmax_rep_int = IZR pow2sb.
Proof.
  rewrite IZR_pow2sb.
  unfold B2R; simpl.
  rewrite shift_pos_correct.
  rewrite Z.pow_pos_fold.
  unfold F2R.
  unfold Fnum, Fexp.
  rewrite Zmult_1_r.
  change 2%Z with (radix_val radix2).
  rewrite IZR_Zpower by easy.
  rewrite <-bpow_plus.
  rewrite Pos2Z.inj_sub by exact sb_gt_1.
  replace (Z.pos sb_pos - 1 + 1)%Z with (Z.pos sb_pos).
  reflexivity.
  ring.
Qed.

Lemma pow2sb_lt_max_int: (pow2sb <= max_int)%Z.
Proof.
  apply le_IZR.
  rewrite <-max_real_int, <-Bmax_rep_int_to_real.
  now apply is_finite1.
Qed.

Lemma rep_int_in_range:
  forall i, (- pow2sb <= i <= pow2sb)%Z ->
            in_range (IZR i).
Proof.
  intros.
  rewrite <-Z.abs_le in H.
  pose (IZR_le _ _ H).
  rewrite <-Rabs_Zabs in r.
  unfold in_range.
  apply Rabs_le_inv.
  apply Rle_trans with (r2 := IZR pow2sb); auto.

  rewrite <-Bmax_rep_int_to_real, <-max_value_to_real.
  apply le_to_real; try easy.

  assert (is_finite Bmax_rep_int) by easy.
  pose (bounded_floats _ H0).
  rewrite le_correct.
  easy.
Qed.

(* Why3 goal *)
Lemma Exact_rounding_for_integers :
  forall (m:ieee_float.RoundingMode.mode) (i:Numbers.BinNums.Z),
  in_safe_int_range i -> ((round m (BuiltIn.IZR i)) = (BuiltIn.IZR i)).
Proof with auto with typeclass_instances.
intros m z Hz.
apply round_generic...
assert (Z.abs z <= pow2sb)%Z.
apply Z.abs_le with (1:=Hz).
destruct (Zle_lt_or_eq _ _ H) as [Bz|Bz] ; clear H Hz.
apply generic_format_FLT.
exists (Float radix2 z 0).
unfold F2R ; simpl.
now rewrite Rmult_1_r.
easy.
simpl; unfold emin; generalize Hsb' Hemax'; lia.
unfold pow2sb in Bz.
change 2%Z with (radix_val radix2) in Bz.
apply generic_format_abs_inv.
rewrite <- abs_IZR, Bz, IZR_Zpower.
apply generic_format_bpow.
unfold FLT_exp, emin.
clear Bz; generalize Hsb' Hemax'.
lia.
apply Zlt_le_weak.
apply Hsb'.
Qed.

(* Why3 goal *)
Definition from_real :
  ieee_float.RoundingMode.mode -> Reals.Rdefinitions.R -> t.
Proof.
  exact r_to_fp. 
Defined.

(* Why3 goal *)
Lemma from_real_in_range :
  forall (m:ieee_float.RoundingMode.mode) (r:Reals.Rdefinitions.R),
  in_range (round m r) ->
  let f := from_real m r in is_finite f /\ ((to_real f) = (round m r)).
Proof.
intros m r h1 f.
unfold from_real, round in *.
unfold is_finite, in_range, to_real in *.
apply r_to_fp_correct.
unfold max_real in *.
Admitted.

(* Why3 goal *)
Lemma from_real_large_neg :
  forall (m:ieee_float.RoundingMode.mode) (r:Reals.Rdefinitions.R),
  ((round m r) < (-max_real)%R)%R ->
  let f := from_real m r in is_infinite f /\ is_negative f.
Proof.
intros m r h1 f.
Admitted.

(* Why3 goal *)
Lemma from_real_large_pos :
  forall (m:ieee_float.RoundingMode.mode) (r:Reals.Rdefinitions.R),
  (max_real < (round m r))%R ->
  let f := from_real m r in is_infinite f /\ is_positive f.
Proof.
intros m r h1 f.
Admitted.

Lemma in_safe_int_range_no_overflow : forall m {i}, in_safe_int_range i -> no_overflow m (IZR i).
Proof.
  intros m i h.
  apply Bounded_real_no_overflow.
  unfold in_safe_int_range in h.
  unfold in_range.
  rewrite max_real_int, <- FromInt.Neg.
  pose proof pow2sb_lt_max_int.
  split; apply IZR_le; auto with zarith.
Qed.

(* Why3 assumption *)
Definition same_sign (x:t) (y:t) : Prop :=
  is_positive x /\ is_positive y \/ is_negative x /\ is_negative y.

Hint Unfold same_sign.

Lemma same_sign_refl: forall {x}, ~ is_nan x -> same_sign x x.
Proof.
  unfold is_nan, same_sign.
  intros x h.
  destruct x; try easy; try (destruct s; now auto).
  now contradict h.
Qed.

(* Why3 assumption *)
Definition diff_sign (x:t) (y:t) : Prop :=
  is_positive x /\ is_negative y \/ is_negative x /\ is_positive y.

Hint Unfold same_sign.

(* Why3 goal *)
Lemma feq_eq :
  forall (x:t) (y:t), is_finite x -> is_finite y -> ~ is_zero x -> eq x y ->
  (x = y).
Proof.
intros x y h1 h2 h3 h4.
destruct x, y; try easy.

destruct s, s0; try easy.
destruct s, s0; try easy.

revert h3 h4.
case (Bool.bool_dec s s0); intro h; [rewrite h;clear h|destruct s, s0; try easy; destruct h;reflexivity].
intros h3 h4. clear h1.

destruct (Z_dec e e1) as [He|He].

- unfold eq, Bcompare in h4; simpl in h4.
  destruct He.
  rewrite (Zcompare_Lt _ _ l) in h4.
  destruct s, s0; try easy.
  rewrite (Zcompare_Gt _ _ (Z.gt_lt _ _ g)) in h4.
  destruct s, s0; try easy.

- destruct He.
  case (Pos.eq_dec m m0); intro.
  + destruct e1.
    assert (forall x y: bool, x = y \/ x <> y) by
        (intros; case (Bool.bool_dec x y); auto).
    destruct (Eqdep_dec.eq_proofs_unicity H e0 e2).
    reflexivity.

  + unfold eq, Bcompare in h4; simpl in h4.
    destruct s0.
    * rewrite Z.compare_refl, Some_ext, Pos.compare_cont_antisym in h4.
      rewrite (Pos.compare_eq _ _ h4) in n.
      destruct n; reflexivity.

    * rewrite Z.compare_refl, Some_ext in h4.
      rewrite (Pos.compare_eq _ _ h4) in n.
      destruct n; reflexivity.
Qed.

Lemma to_real_refl: forall {x:t} {y:t}, is_finite x -> is_finite y ->
                                        to_real x = to_real y -> same_sign x y ->
                                        x = y.
Proof.
  intros x y h1 h2 h3 h4.
  destruct x, y; try easy.
  + destruct s, s0, h4; easy.
  + symmetry in h3.
    apply eq_0_F2R in h3.
    destruct s0; contradict h3; easy.
  + apply eq_0_F2R in h3.
    destruct s; contradict h3; easy.
  + apply feq_eq; auto.
    rewrite eq_zero_iff; intro.
    destruct H; easy.
    apply to_real_eq; auto.
Qed.

(* Why3 goal *)
Lemma eq_feq :
  forall (x:t) (y:t), is_finite x -> is_finite y -> (x = y) -> eq x y.
Proof.
intros x y h1 h2 h3.
rewrite h3.
apply (eq_not_nan_refl (is_finite_not_nan h2)).
Qed.

(* Why3 goal *)
Lemma eq_refl : forall (x:t), is_finite x -> eq x x.
Proof.
intros x h1.
apply (eq_not_nan_refl (is_finite_not_nan h1)).
Qed.

(* Why3 goal *)
Lemma eq_sym : forall (x:t) (y:t), eq x y -> eq y x.
Proof.
intros x y.
unfold eq; intro h; rewrite Bcompare_swap, h; easy.
Qed.

(* Why3 goal *)
Lemma eq_trans : forall (x:t) (y:t) (z:t), eq x y -> eq y z -> eq x z.
Proof.
  intros x y z h1 h2.
  destruct x, y, z; auto; try destruct s; try destruct s0; try destruct s1; auto; try easy;
  apply to_real_eq in h1; try (split;easy);
  apply to_real_eq in h2; try (split;easy);
  apply to_real_eq; try (split;easy);
  apply (eq_trans h1 h2).
Qed.

(* Why3 goal *)
Lemma eq_zero : eq zeroF (neg zeroF).
Proof.
easy.
Qed.

(* Why3 goal *)
Lemma eq_to_real_finite :
  forall (x:t) (y:t), is_finite x /\ is_finite y ->
  eq x y <-> ((to_real x) = (to_real y)).
Proof.
intros x y (h1,h2).
apply (to_real_eq h1 h2).
Qed.

(* Why3 goal *)
Lemma eq_special :
  forall (x:t) (y:t), eq x y ->
  is_not_nan x /\
  is_not_nan y /\
  (is_finite x /\ is_finite y \/
   is_infinite x /\ is_infinite y /\ same_sign x y).
Proof.
  intros x y h1.
  rewrite is_not_nan1, is_not_nan1.
  destruct (eq_not_nan h1) as (h2,h3).
  split; [auto|split;auto].
  destruct (not_nan _ h2); [left|right].
  - split; [apply i|apply (eq_finite_dist h1 i)].
  - split; [apply i|split;[apply (eq_infinite_dist h1 i)|]].
    destruct x, y; try destruct s; try destruct s0; auto; easy.
Qed.

(* Why3 goal *)
Lemma lt_finite :
  forall (x:t) (y:t), is_finite x /\ is_finite y ->
  lt x y <-> ((to_real x) < (to_real y))%R.
Proof.
intros x y (h1,h2).
unfold lt.
rewrite (Bcompare_correct _ _ x y h1 h2), Some_ext.
split; intro H; [apply (Rcompare_Lt_inv _ _ H)|
                 apply (Rcompare_Lt _ _ H)].
Qed.

(* Why3 goal *)
Lemma le_finite :
  forall (x:t) (y:t), is_finite x /\ is_finite y ->
  le x y <-> ((to_real x) <= (to_real y))%R.
Proof.
intros x y (h1,h2).
now apply le_to_real.
Qed.

Lemma lt_eq_trans : forall {x y z:t}, lt x y -> eq y z -> lt x z.
Proof.
  intros x y z h1 h2.
  destruct x, y, z; try easy; try (destruct s, s0, s1; easy).
  set (x:=B754_finite s m e e0);
    set (y:=B754_finite s0 m0 e1 e2);
    set (z:=B754_finite s1 m1 e3 e4); fold x y z in h1, h2.
  pose proof (Bcompare_correct sb emax x y).
  pose proof (Bcompare_correct sb emax y z).
  pose proof (Bcompare_correct sb emax x z).
  unfold lt in h1.
  rewrite H in h1 by easy; clear H.
  unfold eq in h2.
  rewrite H0 in h2 by easy; clear H0.
  unfold lt.
  rewrite H1 by easy; clear H1.
  apply f_equal, Rcompare_Lt.
  apply Rlt_le_trans with (B2R (B754_finite s0 m0 e1 e2)).
  + apply Rcompare_Lt_inv.
    now injection h1.
  + apply Rcompare_not_Gt_inv.
    inversion h1; inversion h2.
    destruct Rcompare; try easy.
    destruct Rcompare; try easy;
    simpl; rewrite H1; discriminate.
Qed.

Lemma eq_lt_trans : forall {x y z:t}, eq x y -> lt y z -> lt x z.
Proof.
  intros x y z h1 h2.
  destruct x, y, z; try easy; try (destruct s, s0, s1; easy).
  set (x:=B754_finite s m e e0);
    set (y:=B754_finite s0 m0 e1 e2);
    set (z:=B754_finite s1 m1 e3 e4); fold x y z in h1, h2.
  pose proof (Bcompare_correct sb emax x y).
  pose proof (Bcompare_correct sb emax y z).
  pose proof (Bcompare_correct sb emax x z).
  unfold eq in h1.
  unfold lt in h2.
  rewrite H in h1 by easy; clear H.
  rewrite H0 in h2 by easy; clear H0.
  unfold lt.
  rewrite H1 by easy; clear H1.
  apply f_equal, Rcompare_Lt.
  apply Rle_lt_trans with (B2R (B754_finite s0 m0 e1 e2)).
  + apply Rcompare_not_Gt_inv.
    inversion h1; inversion h2.
    destruct Rcompare; try easy;
    simpl; rewrite H0; discriminate.
  + apply Rcompare_Lt_inv.
    now injection h2.
Qed.

Lemma lt_lt_trans : forall {x y z:t}, lt x y -> lt y z -> lt x z.
Proof.
  intros x y z h1 h2.
  destruct x, y, z; try easy; try (destruct s, s0, s1; easy).
  set (x:=B754_finite s m e e0);
    set (y:=B754_finite s0 m0 e1 e2);
    set (z:=B754_finite s1 m1 e3 e4); fold x y z in h1, h2.
  pose proof (Bcompare_correct sb emax x y).
  pose proof (Bcompare_correct sb emax y z).
  pose proof (Bcompare_correct sb emax x z).
  unfold lt in h1, h2.
  rewrite H in h1 by easy; clear H.
  rewrite H0 in h2 by easy; clear H0.
  unfold lt.
  rewrite H1 by easy; clear H1.
  apply f_equal, Rcompare_Lt.
  apply Rlt_trans with (B2R (B754_finite s0 m0 e1 e2)).
  + apply Rcompare_Lt_inv.
    now injection h1.
  + apply Rcompare_Lt_inv.
    now injection h2.
Qed.

(* Why3 goal *)
Lemma le_lt_trans : forall (x:t) (y:t) (z:t), le x y /\ lt y z -> lt x z.
Proof.
  intros x y z (h,h1).
  apply le_correct in h.
  destruct h as [h|h].
  apply (lt_lt_trans h h1).
  apply (eq_lt_trans h h1).
Qed.

(* Why3 goal *)
Lemma lt_le_trans : forall (x:t) (y:t) (z:t), lt x y /\ le y z -> lt x z.
Proof.
  intros x y z (h1,h2).
  apply le_correct in h2.
  destruct h2 as [h2|h2].
  apply (lt_lt_trans h1 h2).
  apply (lt_eq_trans h1 h2).
Qed.

(* Why3 goal *)
Lemma le_ge_asym : forall (x:t) (y:t), le x y /\ le y x -> eq x y.
Proof.
intros x y.
unfold le, eq.
destruct x, y; intros (h,h1); auto; try easy; try (destruct s,s0,h,h1; easy).
set (x:=B754_finite s m e e0);
  set (y:=B754_finite s0 m0 e1 e2);
  fold x y in h, h1.
pose proof (Bcompare_correct sb emax x y).
pose proof (Bcompare_correct sb emax y x).
rewrite H in h by easy.
rewrite H0 in h1 by easy.
rewrite H by easy.
f_equal.
apply Rcompare_Eq.
apply Rle_antisym.
+ apply Rcompare_not_Gt_inv.
  now destruct Rcompare.
+ apply Rcompare_not_Gt_inv.
  now destruct (Rcompare (B2R y) (B2R x)).
Qed.

Lemma Some_ext_op: forall {T} (a b:T), Some a <> Some b <-> a <> b.
Proof.
  intros; split; intro H.
  intro h.
  apply (H (f_equal _ h)).
  intro h; injection h; auto.
Qed.

(* Why3 goal *)
Lemma not_lt_ge :
  forall (x:t) (y:t), ~ lt x y /\ is_not_nan x /\ is_not_nan y -> le y x.
Proof.
  intros x y.
  rewrite is_not_nan1; rewrite is_not_nan1.
  unfold is_nan.
  destruct x, y; intros (h,(h1,h2)); try (try destruct s; try destruct s0; try easy; elim h1; auto; easy).
  revert h.
  unfold le, lt.
  rewrite Bcompare_swap.
  rewrite Bcompare_correct by easy.
  now destruct Rcompare as [| |].
Qed.

(* Why3 goal *)
Lemma not_gt_le :
  forall (x:t) (y:t), ~ lt y x /\ is_not_nan x /\ is_not_nan y -> le x y.
Proof.
  intros x y.
  rewrite is_not_nan1; rewrite is_not_nan1.
  unfold is_nan.
  destruct x, y; intros (h,(h1,h2)); auto; try (try destruct s; try destruct s0; try easy; elim h1; auto; easy).
  revert h.
  unfold le, lt.
  rewrite Bcompare_swap.
  rewrite Bcompare_correct by easy.
  now destruct Rcompare as [| |].
Qed.

(* Why3 goal *)
Lemma le_special :
  forall (x:t) (y:t), le x y ->
  is_finite x /\ is_finite y \/
  is_minus_infinity x /\ is_not_nan y \/ is_not_nan x /\ is_plus_infinity y.
Proof.
  intros x y h.
  rewrite is_not_nan1; rewrite is_not_nan1.
  unfold le in h.
  unfold is_nan, is_finite.
  destruct x, y; auto; try easy; try (destruct s, s0; auto; destruct h; auto; easy).
  - right; right. destruct s0, h; split; easy.
  - right; left. destruct s, h; split; easy.
  - right. destruct s, s0, h; try easy.
    + left; split; easy.
    + left; split; easy.
    + right; split; easy.
  - right; left. destruct s, h; split; easy.
  - right; right. destruct s, s0, h; split; easy.
Qed.

(* Why3 goal *)
Lemma lt_special :
  forall (x:t) (y:t), lt x y ->
  is_finite x /\ is_finite y \/
  is_minus_infinity x /\ is_not_nan y /\ ~ is_minus_infinity y \/
  is_not_nan x /\ ~ is_plus_infinity x /\ is_plus_infinity y.
Proof.
  intros x y h.
  rewrite is_not_nan1; rewrite is_not_nan1.
  unfold lt in h.
  unfold is_nan, is_finite.
  unfold is_plus_infinity, is_minus_infinity.
  destruct x, y; auto; try easy; try (destruct s, s0; easy).

  - right; right. destruct s0; split; try split; easy.
  - right; left. destruct s; split; try split; easy.
  - right; right. destruct s, s0; split; try split; easy.
  - right; left. destruct s; split; try split; easy.
  - right; right. destruct s, s0; split; try split; easy.
Qed.

(* Why3 goal *)
Lemma lt_lt_finite :
  forall (x:t) (y:t) (z:t), lt x y -> lt y z -> is_finite y.
Proof.
intros x y z h1 h2.
destruct x, y, z; try easy; destruct s, s0, s1; easy.
Qed.

(* Why3 goal *)
Lemma positive_to_real :
  forall (x:t), is_finite x -> is_positive x -> (0%R <= (to_real x))%R.
Proof.
  intros x h1 h2.
  assert (is_finite zeroF) as zero_is_finite by easy.
  rewrite <-zeroF_to_real; apply (le_to_real _ _ zero_is_finite h1).
  apply le_correct.
  generalize (is_positive_correct x); intro H. destruct H, H; auto.
  rewrite H; auto.
Qed.

Lemma non_zero_positive_to_real : forall {x:t},
    is_finite x -> ~ is_zero x -> is_positive x ->
     0 < to_real x.
Proof.
  intros x h1 h2 h3.
  rewrite <-zeroF_to_real; apply lt_finite.
  split; easy.
  destruct x; try easy.
  contradict h2; easy.
  simpl in h3.
  destruct s; simpl; easy.
Qed.

Lemma is_positive_to_int: forall {x} {m:mode}, is_finite x -> is_positive x -> (0 <= to_int m x)%Z.
Proof.
  intros x m h h1.
  rewrite <-(to_int_zeroF m).
  destruct (valid_rnd_round_mode m) as (h2,_).
  destruct m; simpl in h2; apply h2; now apply positive_to_real.
Qed.

(* Why3 goal *)
Lemma to_real_positive :
  forall (x:t), is_finite x -> (0%R < (to_real x))%R -> is_positive x.
Proof.
  intros x h1 h2.
  assert (is_finite zeroF) as zero_is_finite by easy.
  rewrite <-zeroF_to_real, <-(lt_finite _ _ (conj zero_is_finite h1)) in h2.
  generalize (is_positive_correct x); intro H; destruct H; auto.
Qed.

(* Why3 goal *)
Lemma negative_to_real :
  forall (x:t), is_finite x -> is_negative x -> ((to_real x) <= 0%R)%R.
Proof.
  intros x h1 h2.
  assert (is_finite zeroF) as zero_is_finite by easy.
  rewrite <-zeroF_to_real; apply (le_to_real _ _ h1 zero_is_finite).
  apply le_correct.
  generalize (is_negative_correct x); intro H; destruct H, H; auto.
  rewrite H; auto.
Qed.

Lemma non_zero_negative_to_real : forall {x:t},
    is_finite x -> ~ is_zero x -> is_negative x ->
     to_real x < 0.
Proof.
  intros x h1 h2 h3.
  rewrite <-zeroF_to_real; apply lt_finite.
  split; easy.
  destruct x; try easy.
  contradict h2; easy.
  simpl in h3.
  destruct s; simpl; easy.
Qed.

Lemma is_negative_to_int: forall {x} {m:mode}, is_finite x -> is_negative x -> (to_int m x <= 0)%Z.
Proof.
  intros x m h h1.
  rewrite <-(to_int_zeroF m).
  destruct (valid_rnd_round_mode m) as (h2,_).
  destruct m; simpl in h2; apply h2; now apply negative_to_real.
Qed.

(* Why3 goal *)
Lemma to_real_negative :
  forall (x:t), is_finite x -> ((to_real x) < 0%R)%R -> is_negative x.
Proof.
  intros x h1 h2.
  assert (is_finite zeroF) as zero_is_finite by easy.
  rewrite <-zeroF_to_real, <-(lt_finite _ _ (conj h1 zero_is_finite)) in h2.
  generalize (is_negative_correct x); intro H; destruct H; auto.
Qed.

(* Why3 goal *)
Lemma negative_xor_positive :
  forall (x:t), ~ (is_positive x /\ is_negative x).
Proof.
intros x.
destruct x; try destruct s; easy.
Qed.

(* Why3 goal *)
Lemma negative_or_positive :
  forall (x:t), is_not_nan x -> is_positive x \/ is_negative x.
Proof.
intros x h1.
destruct x; try destruct s; simpl; auto; now elim h1.
Qed.

(* Why3 goal *)
Lemma diff_sign_trans :
  forall (x:t) (y:t) (z:t), diff_sign x y /\ diff_sign y z -> same_sign x z.
Proof.
  unfold diff_sign, same_sign.
  intros x y z (h1,h2).
  pose proof (negative_xor_positive y) as H.
  destruct h1 as [(h,h1)|(h,h1)], h2 as [(h2,h3)|(h2,h3)].
  - contradict H; split; easy.
  - left; split; easy.
  - right; split; easy.
  - contradict H; split; easy.
Qed.

(* Why3 goal *)
Lemma diff_sign_product :
  forall (x:t) (y:t),
  is_finite x /\ is_finite y /\ (((to_real x) * (to_real y))%R < 0%R)%R ->
  diff_sign x y.
Proof.
intros x y (h1,(h2,h3)).
unfold diff_sign.
case (Rcase_abs (to_real y)); intro; [left|right].
- split; [apply to_real_positive; try easy|apply to_real_negative; easy].
  apply Rmult_lt_reg_r with (r := (-to_real y)); lra.
- destruct r.
  + split; [apply to_real_negative; try easy|apply to_real_positive; easy].
    apply Rmult_lt_reg_r with (r := (to_real y)); lra.
  + rewrite H in h3; lra.
Qed.

(* Why3 goal *)
Lemma same_sign_product :
  forall (x:t) (y:t), is_finite x /\ is_finite y /\ same_sign x y ->
  (0%R <= ((to_real x) * (to_real y))%R)%R.
Proof.
intros x y (h1,(h2,h3)).
unfold same_sign in h3.
destruct h3 as [(h3,h4)|(h3,h4)].
- apply (positive_to_real _ h1) in h3.
  apply (positive_to_real _ h2) in h4.
  apply Rmult_le_pos; auto.
- apply (negative_to_real _ h1) in h3.
  apply (negative_to_real _ h2) in h4.
  rewrite <-Rmult_opp_opp.
  apply Rmult_le_pos; lra.
Qed.

(* Why3 assumption *)
Definition product_sign (z:t) (x:t) (y:t) : Prop :=
  (same_sign x y -> is_positive z) /\ (diff_sign x y -> is_negative z).

(* Why3 assumption *)
Definition overflow_value (m:ieee_float.RoundingMode.mode) (x:t) : Prop :=
  match m with
  | ieee_float.RoundingMode.RTN =>
      (is_positive x -> is_finite x /\ ((to_real x) = max_real)) /\
      (~ is_positive x -> is_infinite x)
  | ieee_float.RoundingMode.RTP =>
      (is_positive x -> is_infinite x) /\
      (~ is_positive x -> is_finite x /\ ((to_real x) = (-max_real)%R))
  | ieee_float.RoundingMode.RTZ =>
      (is_positive x -> is_finite x /\ ((to_real x) = max_real)) /\
      (~ is_positive x -> is_finite x /\ ((to_real x) = (-max_real)%R))
  | ieee_float.RoundingMode.RNA|ieee_float.RoundingMode.RNE => is_infinite x
  end.

(* Why3 assumption *)
Definition sign_zero_result (m:ieee_float.RoundingMode.mode) (x:t) : Prop :=
  is_zero x ->
  match m with
  | ieee_float.RoundingMode.RTN => is_negative x
  | _ => is_positive x
  end.

(* Why3 goal *)
Lemma add_finite :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t), is_finite x ->
  is_finite y -> no_overflow m ((to_real x) + (to_real y))%R ->
  is_finite (add m x y) /\
  ((to_real (add m x y)) = (round m ((to_real x) + (to_real y))%R)).
Proof.
intros m x y h1 h2 h3.
generalize (Bplus_correct sb emax Hsb'' Hemax' m x y h1 h2); rewrite Rlt_bool_true.
intro; split; easy.
apply (in_range_bpow_radix2_emax _ h3).
Qed.

(* Why3 goal *)
Lemma add_finite_rev :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t),
  is_finite (add m x y) -> is_finite x /\ is_finite y.
Proof.
intros m x y h1.
destruct x, y; try easy; destruct s, s0; try easy;
  simpl in h1; unfold is_finite in h1; now rewrite is_finite_build_nan in h1.
Qed.

(* Why3 goal *)
Lemma add_finite_rev_n :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t),
  ieee_float.RoundingMode.to_nearest m -> is_finite (add m x y) ->
  no_overflow m ((to_real x) + (to_real y))%R /\
  ((to_real (add m x y)) = (round m ((to_real x) + (to_real y))%R)).
Proof.
intros m x y h1 h2.
destruct (add_finite_rev m x y h2).
assert (no_overflow m (to_real x + to_real y)).
2: split; [easy|apply add_finite; easy].
pose proof max_real_ge_6.
destruct x, y; try easy; try (rewrite B754_zero_to_real).
apply Bounded_real_no_overflow; rewrite (@B754_zero_to_real s0); split; lra.
apply Bounded_real_no_overflow; rewrite Rplus_0_l; apply is_finite1; auto.
apply Bounded_real_no_overflow; rewrite Rplus_0_r; apply is_finite1; auto.
set (x := B754_finite s m0 e e0).
set (y := B754_finite s0 m1 e1 e2).
fold x y in h2, H, H0.
destruct (Rlt_le_dec (Rabs (round m (to_real x + to_real y))) (bpow radix2 emax)).
rewrite no_overflow_Rabs_round_emax; assumption.
pose proof (Bplus_correct sb emax Hsb'' Hemax' m x y H H0).
change (Bplus m) with (add m) in H2.
rewrite Rlt_bool_false in H2; auto.
destruct m, h1; try easy.
destruct (add RNE x y); easy.
destruct (add RNA x y); easy.
Qed.

(* Why3 goal *)
Lemma sub_finite :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t), is_finite x ->
  is_finite y -> no_overflow m ((to_real x) - (to_real y))%R ->
  is_finite (sub m x y) /\
  ((to_real (sub m x y)) = (round m ((to_real x) - (to_real y))%R)).
Proof.
intros m x y h1 h2 h3.
generalize (Bminus_correct sb emax Hsb'' Hemax' m x y h1 h2); rewrite Rlt_bool_true.
intro; split; easy.
apply (in_range_bpow_radix2_emax _ h3).
Qed.

(* Why3 goal *)
Lemma sub_finite_rev :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t),
  is_finite (sub m x y) -> is_finite x /\ is_finite y.
Proof.
  intros m x y h1.
  destruct x, y; try easy; destruct s, s0; try easy;
    simpl in h1; unfold is_finite in h1; now rewrite is_finite_build_nan in h1.
Qed.

(* Why3 goal *)
Lemma sub_finite_rev_n :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t),
  ieee_float.RoundingMode.to_nearest m -> is_finite (sub m x y) ->
  no_overflow m ((to_real x) - (to_real y))%R /\
  ((to_real (sub m x y)) = (round m ((to_real x) - (to_real y))%R)).
Proof.
intros m x y h1 h2.
destruct (sub_finite_rev m x y h2).
assert (no_overflow m (to_real x - to_real y)).
2: split; [easy|apply sub_finite; easy].
pose proof max_real_ge_6.
destruct x, y; try easy; try (rewrite B754_zero_to_real).
apply Bounded_real_no_overflow; rewrite (@B754_zero_to_real s0); split; lra.
apply Bounded_real_no_overflow.
unfold to_real.
rewrite Rminus_0_l, <- B2R_Bopp.
apply is_finite1, is_finite_Bopp.
apply Bounded_real_no_overflow; rewrite Rminus_0_r; apply is_finite1; auto.
set (x := B754_finite s m0 e e0).
set (y := B754_finite s0 m1 e1 e2).
fold x y in h2, H, H0.
destruct (Rlt_le_dec (Rabs (round m (to_real x - to_real y))) (bpow radix2 emax)).
rewrite no_overflow_Rabs_round_emax; assumption.
pose proof (Bminus_correct sb emax Hsb'' Hemax' m x y H H0).
change (Bminus m) with (sub m) in H2.
rewrite Rlt_bool_false in H2; auto.
destruct m, h1; try easy.
destruct (sub RNE x y); easy.
destruct (sub RNA x y); easy.
Qed.

(* Why3 goal *)
Lemma mul_finite :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t), is_finite x ->
  is_finite y -> no_overflow m ((to_real x) * (to_real y))%R ->
  is_finite (mul m x y) /\
  ((to_real (mul m x y)) = (round m ((to_real x) * (to_real y))%R)).
Proof.
intros m x y h1 h2 h3.
generalize (Bmult_correct sb emax Hsb'' Hemax' m x y); rewrite Rlt_bool_true, h1, h2.
intro; split; easy.
apply (in_range_bpow_radix2_emax _ h3).
Qed.

(* Why3 goal *)
Lemma mul_finite_rev :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t),
  is_finite (mul m x y) -> is_finite x /\ is_finite y.
Proof.
  intros m x y h1.
  destruct x, y; try easy; destruct s, s0; try easy;
    simpl in h1; unfold is_finite in h1; now rewrite is_finite_build_nan in h1.
Qed.

(* Why3 goal *)
Lemma mul_finite_rev_n :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t),
  ieee_float.RoundingMode.to_nearest m -> is_finite (mul m x y) ->
  no_overflow m ((to_real x) * (to_real y))%R /\
  ((to_real (mul m x y)) = (round m ((to_real x) * (to_real y))%R)).
Proof.
intros m x y h1 h2.
destruct (mul_finite_rev m x y h2).
assert (no_overflow m (to_real x * to_real y)).
2: split; [easy|apply mul_finite; easy].
pose proof max_real_ge_6.
destruct x, y; try easy; try (rewrite B754_zero_to_real).
apply Bounded_real_no_overflow; rewrite (@B754_zero_to_real s0); split; lra.
unfold no_overflow; rewrite Rmult_0_l, <-zeroF_to_real, Round_to_real, zeroF_to_real; auto; split; lra.
unfold no_overflow; rewrite Rmult_0_r, <-zeroF_to_real, Round_to_real, zeroF_to_real; auto; split; lra.
set (x := B754_finite s m0 e e0).
set (y := B754_finite s0 m1 e1 e2).
fold x y in h2, H, H0.
destruct (Rlt_le_dec (Rabs (round m (to_real x * to_real y))) (bpow radix2 emax)).
rewrite no_overflow_Rabs_round_emax; assumption.
pose proof (Bmult_correct sb emax Hsb'' Hemax' m x y).
change (Bmult m) with (mul m) in H2.
rewrite Rlt_bool_false in H2; auto.
destruct m, h1; try easy.
destruct (mul RNE x y); easy.
destruct (mul RNA x y); easy.
Qed.

(* Why3 goal *)
Lemma div_finite :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t), is_finite x ->
  is_finite y -> ~ is_zero y ->
  no_overflow m ((to_real x) / (to_real y))%R ->
  is_finite (div m x y) /\
  ((to_real (div m x y)) = (round m ((to_real x) / (to_real y))%R)).
Proof.
  intros m x y h1 h2 h3 h4.
  assert (is_finite zeroF) as zero_is_finite by easy.
  rewrite (to_real_eq zero_is_finite h2) in h3.
  apply not_eq_sym in h3.
  generalize (Bdiv_correct sb emax Hsb'' Hemax' m x y h3); rewrite Rlt_bool_true, h1.
  intro; split; easy.
  apply (in_range_bpow_radix2_emax _ h4).
Qed.

(* Why3 goal *)
Lemma div_finite_rev :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t),
  is_finite (div m x y) ->
  is_finite x /\ is_finite y /\ ~ is_zero y \/
  is_finite x /\ is_infinite y /\ ((to_real (div m x y)) = 0%R).
Proof.
  intros m x y h1.
  destruct x, y; try easy;
    simpl in h1; unfold is_finite in h1; try now rewrite is_finite_build_nan in h1.
  right; destruct s, s0; easy.
  left; destruct s, s0; split; try split; easy.
  right; destruct s, s0; split; try split; easy.
  left; destruct s, s0; split; try split; easy.
Qed.

(* Why3 goal *)
Lemma div_finite_rev_n :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t),
  ieee_float.RoundingMode.to_nearest m -> is_finite (div m x y) ->
  is_finite y ->
  no_overflow m ((to_real x) / (to_real y))%R /\
  ((to_real (div m x y)) = (round m ((to_real x) / (to_real y))%R)).
Proof.
  intros m x y h1 h2 h3.
  destruct (div_finite_rev m x y h2) as [(h4,(h5,h6))|(h4,(h5,h6))].
  + assert (no_overflow m (to_real x / to_real y)).
    2: split; [easy|apply div_finite; easy].
    pose proof max_real_ge_6.
    destruct x, y; try easy; try (rewrite B754_zero_to_real).
    rewrite Real.infix_sl'def, Rmult_0_l.
    apply Bounded_real_no_overflow; split; lra.
    set (x := B754_finite s m0 e e0).
    set (y := B754_finite s0 m1 e1 e2).
    fold x y in h2, h3,h4,h5,h6.
    destruct (Rlt_le_dec (Rabs (round m (to_real x / to_real y))) (bpow radix2 emax)).
    rewrite no_overflow_Rabs_round_emax; assumption.
    assert (to_real y <> 0) by (rewrite zero_to_real in h6; auto).
    pose proof (Bdiv_correct sb emax Hsb'' Hemax' m x y H0).
    change (Bdiv m) with (div m) in H1.
    rewrite Rlt_bool_false in H1; auto.
    destruct m, h1; try easy.
    destruct (div RNE x y); easy.
    destruct (div RNA x y); easy.
  + destruct y; easy.
Qed.

(* Why3 goal *)
Lemma neg_finite :
  forall (x:t), is_finite x ->
  is_finite (neg x) /\ ((to_real (neg x)) = (-(to_real x))%R).
Proof.
intros x h1.
split.
unfold neg, is_finite.
rewrite is_finite_Bopp; apply h1.
apply B2R_Bopp.
Qed.

(* Why3 goal *)
Lemma neg_finite_rev :
  forall (x:t), is_finite (neg x) ->
  is_finite x /\ ((to_real (neg x)) = (-(to_real x))%R).
Proof.
  intros x h1.
  assert (is_finite x) by now destruct x.
  split; [easy| apply neg_finite; auto].
Qed.

(* Why3 goal *)
Lemma abs_finite :
  forall (x:t), is_finite x ->
  is_finite (abs x) /\
  ((to_real (abs x)) = (Reals.Rbasic_fun.Rabs (to_real x))) /\
  is_positive (abs x).
Proof.
  intros x h1.
  pose proof (is_finite_abs x h1).
  split;[assumption|split].
  apply B2R_Babs.
  pose proof (is_finite_not_nan h1).
  pose proof (Bsign_Babs sb emax x).
  apply is_positive_Bsign.
  apply (is_finite_not_nan H).
  apply H1.
Qed.

(* add to theory ? *)
Lemma abs_le: forall {x y}, le (neg y) x /\ le x y -> le (abs x) y.
Proof.
  intros x y.
  destruct (Finite_Infinite_Nan_dec y) as [[hy|hy]|hy].
  + destruct (Finite_Infinite_Nan_dec x) as [[hx|hx]|hx].

    * pose proof (is_finite_abs _ hx).
      destruct (neg_finite _ hy).
      rewrite (le_to_real (abs x) y) by auto.
      rewrite (le_to_real (neg y) x) by auto.
      rewrite le_to_real by auto.
      rewrite H1 by auto.
      destruct (abs_finite _ hx) as (_,(u,_)).
      rewrite u.
      apply Rabs_le.

    * intros (a,b).
      destruct (le_special _ _ b) as [H|[H|H]].
      - destruct x; easy.
      - pose proof (le_special _ _ a).
        unfold is_minus_infinity, is_plus_infinity in H0.
        destruct H0, H0, x, y; auto; try easy; destruct s, s0; auto.
      - destruct y; unfold is_plus_infinity in H; easy.

    * intros (a,b).
      destruct (le_special _ _ b) as [H|[H|H]];
        unfold is_minus_infinity in H;
        destruct x; easy.

  + intros (a,b).

    destruct (Finite_Infinite_Nan_dec x) as [[hx|hx]|hx].
    * destruct (le_special _ _ b) as [H|[H|H]].
      - destruct y; easy.
      - unfold is_minus_infinity in H; destruct x; easy.
      - destruct y, H as (H,(_,H')); try destruct s; try easy.
        assert (~ is_nan x) by (rewrite <-is_not_nan1; assumption).
        apply le_infinity.
        destruct x; easy.
    * destruct x, y; try easy.
      destruct s; try easy.
      now destruct s0.
    * now destruct x.

  + intros (_,a).
    destruct y; try easy.
    now destruct x.
Qed.

(* Why3 goal *)
Lemma abs_finite_rev :
  forall (x:t), is_finite (abs x) ->
  is_finite x /\ ((to_real (abs x)) = (Reals.Rbasic_fun.Rabs (to_real x))).
Proof.
intros x h1.
assert (is_finite x) by now destruct x.
split; [easy| apply abs_finite; auto].
Qed.

(* Why3 goal *)
Lemma abs_universal : forall (x:t), ~ is_negative (abs x).
Proof.
intros x.
now destruct x.
Qed.

(* Why3 goal *)
Lemma fma_finite :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t) (z:t), is_finite x ->
  is_finite y -> is_finite z ->
  no_overflow m (((to_real x) * (to_real y))%R + (to_real z))%R ->
  is_finite (fma m x y z) /\
  ((to_real (fma m x y z)) =
   (round m (((to_real x) * (to_real y))%R + (to_real z))%R)).
Proof.
intros m x y z h1 h2 h3 h4.
Admitted.

(* Why3 goal *)
Lemma fma_finite_rev :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t) (z:t),
  is_finite (fma m x y z) -> is_finite x /\ is_finite y /\ is_finite z.
Proof.
intros m x y z h1.
Admitted.

(* Why3 goal *)
Lemma fma_finite_rev_n :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t) (z:t),
  ieee_float.RoundingMode.to_nearest m -> is_finite (fma m x y z) ->
  no_overflow m (((to_real x) * (to_real y))%R + (to_real z))%R /\
  ((to_real (fma m x y z)) =
   (round m (((to_real x) * (to_real y))%R + (to_real z))%R)).
Proof.
intros m x y z h1 h2.
Admitted.

(* Why3 goal *)
Lemma sqrt_finite :
  forall (m:ieee_float.RoundingMode.mode) (x:t), is_finite x ->
  (0%R <= (to_real x))%R ->
  is_finite (sqrt m x) /\
  ((to_real (sqrt m x)) = (round m (Reals.R_sqrt.sqrt (to_real x)))).
Proof.
  intros m x h1 h2.
  destruct (Bsqrt_correct sb emax Hsb' Hemax' m x) as (g,(g1,g2)).
  split; auto.
  destruct x; try destruct s; try easy.
  contradict h2.
  apply Rlt_not_le, non_zero_negative_to_real; easy.
Qed.

(* Why3 goal *)
Lemma sqrt_finite_rev :
  forall (m:ieee_float.RoundingMode.mode) (x:t), is_finite (sqrt m x) ->
  is_finite x /\
  (0%R <= (to_real x))%R /\
  ((to_real (sqrt m x)) = (round m (Reals.R_sqrt.sqrt (to_real x)))).
Proof.
  intros m x h1.
  assert (is_finite x).
    destruct x; try destruct s ; try easy;
    simpl in h1; unfold is_finite in h1;
    now rewrite is_finite_build_nan in h1.
  split; [easy|].
  assert (0 <= to_real x).
  { destruct x ; try destruct s; try easy; try apply Rle_refl.
    now apply F2R_ge_0. }
  split; [easy| apply sqrt_finite; auto].
Qed.

(* Why3 assumption *)
Definition same_sign_real (x:t) (r:Reals.Rdefinitions.R) : Prop :=
  is_positive x /\ (0%R < r)%R \/ is_negative x /\ (r < 0%R)%R.

Lemma sign_FF_overflow : forall m b,
    sign_SF (binary_overflow sb emax m b) = b.
Proof.
  intros m b.
  unfold binary_overflow.
  destruct (overflow_to_inf m b); auto.
Qed.

Lemma sign_FF_B2FF : forall x:t, sign_SF (B2SF x) = Bsign x.
Proof.
  now destruct x.
Qed.

(* Why3 goal *)
Lemma add_special :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t),
  let r := add m x y in
  (is_nan x \/ is_nan y -> is_nan r) /\
  (is_finite x /\ is_infinite y -> is_infinite r /\ same_sign r y) /\
  (is_infinite x /\ is_finite y -> is_infinite r /\ same_sign r x) /\
  (is_infinite x /\ is_infinite y /\ same_sign x y ->
   is_infinite r /\ same_sign r x) /\
  (is_infinite x /\ is_infinite y /\ diff_sign x y -> is_nan r) /\
  (is_finite x /\
   is_finite y /\ ~ no_overflow m ((to_real x) + (to_real y))%R ->
   same_sign_real r ((to_real x) + (to_real y))%R /\ overflow_value m r) /\
  (is_finite x /\ is_finite y ->
   (same_sign x y -> same_sign r x) /\
   (~ same_sign x y -> sign_zero_result m r)).
Proof.
intros m x y r.
  unfold same_sign, diff_sign, same_sign, same_sign_real.
  split;[intro h|split;[intros (h,h1)|split;[intros (h,h1)|split;[intros (h,(h1,h2))|split;[intros (h,(h1,h2))|split;[intros (h,(h1,h2))|split;[intro h|intro h]]]]]]].
  - destruct x, y; try easy; destruct s, s0, h; easy.
  - destruct x, y; try easy; destruct s0; auto; easy.
  - destruct x, y; try easy; destruct s; auto; easy.
  - destruct x, y; try easy; destruct s, s0; destruct h2 as [(h2,h3)|(h2,h3)]; auto; easy.
  - destruct x, y; try easy; destruct s, s0; destruct h2 as [(h2,h3)|(h2,h3)]; auto; easy.
  - rewrite no_overflow_Rabs_round_max_real, Rabs_round_max_real_emax in h2.
    apply Rnot_lt_le in h2.
    pose proof (Bplus_correct sb emax Hsb' Hemax' m x y h h1).
    rewrite Rlt_bool_false in H by auto.
    destruct H.
    split.

    + destruct x, y; try easy.
      * destruct s, s0, m; simpl in H; easy.
      * rewrite B754_zero_to_real at 1 2.
        rewrite Rplus_0_l.
        rewrite <-(@B754_zero_to_real false) at 1 2.
        destruct s0;[right;split;[easy|]|left;split;[easy|]]; apply lt_finite; easy.
      * rewrite B754_zero_to_real at 1 2.
        rewrite Rplus_0_r.
        rewrite <-(@B754_zero_to_real false) at 1 2.
        destruct s;[right;split;[easy|]|left;split;[easy|]]; apply lt_finite; easy.
      * change (Bplus m (B754_finite s m0 e e0) (B754_finite s0 m1 e1 e2)) with r in H.
        pose proof (sign_FF_overflow m (Bsign (B754_finite s m0 e e0))).
        rewrite <-H in H1.
        rewrite sign_FF_B2FF in H1.
        simpl Bsign at 2 in H1.
        assert (~is_nan r).
        { simpl binary_overflow in H.
          unfold binary_overflow in H.
          destruct overflow_to_inf in H;
            destruct r; try easy;
              destruct n; easy. }

        simpl in H0. {
        destruct s;rewrite <-H0;[right|left]; split.

        - rewrite <-is_negative_Bsign in H1; auto.
        - assert (to_real (B754_finite true m0 e e0) < 0) by
              (apply non_zero_negative_to_real; easy).
          assert (to_real (B754_finite true m1 e1 e2) < 0) by
              (apply non_zero_negative_to_real; easy).
          lra.
        - rewrite <-is_positive_Bsign in H1; auto.
        - assert (0 < to_real (B754_finite false m0 e e0)) by
              (apply non_zero_positive_to_real; easy).
          assert (0 < to_real (B754_finite false m1 e1 e2)) by
              (apply non_zero_positive_to_real; easy).
          lra. }

    + change (Bplus m x y) with r in H.
      assert (H':=H).
      apply (f_equal sign_SF) in H'.
      rewrite sign_FF_B2FF, sign_FF_overflow in H'.
      destruct m; simpl;
        unfold binary_overflow in H;
        simpl in H.
      * destruct r; try easy; destruct n; easy.
      * destruct r; try easy; destruct n; easy.
      * assert (Bsign x = true \/ Bsign x = false) by
            (destruct x ; try destruct s; simpl; auto). {
        destruct H1; rewrite H1 in H', H0, H; simpl in H.
        - split.
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign, H'; easy.
          intro; split.
          destruct r; try easy; destruct n; easy.
          replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H.
          + unfold to_real. rewrite <-min_real_is_F2R, <- SF2R_B2SF, H; auto.
          + rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto.
          now apply Pos.pow_gt_1.
        - split.
          destruct r; easy.
          intro.
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign in H2; auto; easy. }
      * assert (Bsign x = true \/ Bsign x = false) by
            (destruct x ; try destruct s; simpl; auto). {
        destruct H1; rewrite H1 in H', H0, H; simpl in H.
        - split.
          intro.
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign in H2; auto. rewrite H' in H2; easy.
          destruct r; try easy; destruct n; easy.
        - split.
          intro; split.
          destruct r; easy.
          replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H.
          + unfold to_real. rewrite <-max_real_is_F2R, <- SF2R_B2SF, H; auto.
          + rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto.
            now apply Pos.pow_gt_1.
          + assert (~is_nan r) by
                (destruct r; try easy; destruct n; easy).
            rewrite is_positive_Bsign; easy. }
      * assert (Bsign x = true \/ Bsign x = false) by
            (destruct x ; try destruct s; simpl; auto).
        assert (~is_nan r) by
            (destruct H1, r; try easy; destruct n; easy).
        rewrite is_positive_Bsign; auto. {
        destruct H1; rewrite H1 in H', H0, H; simpl in H.
        - split.
          rewrite H'; easy.
          intro; split.
          destruct r; try easy; destruct n; easy.
          replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H.
          + unfold to_real. rewrite <-min_real_is_F2R, <- SF2R_B2SF, H; auto.
          + rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto.
            now apply Pos.pow_gt_1.
        - split.
          + intro; split.
            destruct r; try easy; destruct n; easy.
            replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H.
            * unfold to_real. rewrite <-max_real_is_F2R, <- SF2R_B2SF, H; auto.
            *  rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto.
               now apply Pos.pow_gt_1.
           + easy. }
  - destruct H.
    pose proof (Bplus_correct sb emax Hsb' Hemax' m x y H H0).
    destruct (Rlt_le_dec (Rabs (round m (to_real x + to_real y))) (bpow radix2 emax)).
    + rewrite Rlt_bool_true in H1; auto.
      destruct H1 as (h1,(h2,h3)).
      change (Bplus m x y) with r in h1, h2, h3.
      assert (~is_nan r) by (destruct r; easy).
      destruct h as [(h,h')|(h,h')];[left|right];split;auto.
      * rewrite is_positive_Bsign; auto.
        destruct y; try destruct s; destruct x; try destruct s; try easy.
        rewrite Rcompare_Gt in h3; auto.
        assert (0 < B2R (B754_finite false m0 e e0)) by
            (apply non_zero_positive_to_real; easy).
        assert (0 < B2R (B754_finite false m1 e1 e2)) by
            (apply non_zero_positive_to_real; easy).
        lra.
      * rewrite is_negative_Bsign; auto.
        destruct y; try destruct s; destruct x; try destruct s; try easy.
        rewrite Rcompare_Lt in h3; auto.
        assert (B2R (B754_finite true  m0 e e0) < 0) by
            (apply non_zero_negative_to_real; easy).
        assert (B2R (B754_finite true m1 e1 e2) < 0) by
            (apply non_zero_negative_to_real; easy).
        lra.
    + rewrite Rlt_bool_false in H1; auto.
      destruct H1 as (h1,h2).
      change (Bplus m x y) with r in h1.
      destruct (is_nan_dec r).
      destruct x; try destruct s; destruct y; try destruct s; try easy; destruct m;
        unfold binary_overflow in h1; simpl in h1;
          destruct r; try easy; destruct n; easy.

      rewrite is_positive_Bsign; auto.
      rewrite is_negative_Bsign; auto.
      apply (f_equal sign_SF) in h1.
      rewrite sign_FF_B2FF, sign_FF_overflow in h1.
      assert (~is_nan x) by (destruct x; easy).
      rewrite is_positive_Bsign in h; auto.
      rewrite is_negative_Bsign in h; auto.
      destruct h as [(h,h')|(h,h')];rewrite h in h1, h2;[left|right];split;auto.
      rewrite is_positive_Bsign; auto.
      rewrite is_negative_Bsign; auto.
  - intuition.
    unfold sign_zero_result; intro.
    unfold is_zero in H2.
    rewrite eq_zero_iff in H2.
    pose proof (Bplus_correct sb emax Hsb' Hemax' m x y H0 H1).
    destruct (Rlt_dec (Rabs (round m (to_real x + to_real y))) (bpow radix2 emax)) as [r0|r0];
      [rewrite Rlt_bool_true in H4; auto; clear r0|
       rewrite Rlt_bool_false in H4].
    + destruct H4 as (h1,(h2,h)).

      assert (to_real x + to_real y = 0).
      { cut (not (to_real x + to_real y <> 0)).
        lra.
        intros H9.
        apply (round_plus_neq_0 radix2 fexp (round_mode m)) in H9.
        apply H9.
        destruct H2 as [H2|H2]; apply (f_equal to_real) in H2.
        rewrite zeroF_to_real in H2.
        rewrite <-H2; auto.
        assert (is_finite zeroF) as zero_is_finite by easy.
        destruct (neg_finite zeroF zero_is_finite).
        rewrite H5, zeroF_to_real, Ropp_0 in H2.
        rewrite <-H2; auto.
        apply generic_format_B2R.
        apply generic_format_B2R. }

      rewrite Rcompare_Eq in h; auto.
      replace (add m x y) with r in h by auto.

      assert (~is_nan r) by (destruct H2, r; easy).

      destruct x ; try destruct s; destruct y ; try destruct s;
        try (simpl in H; contradict H; now auto);
        try (destruct m; simpl in r; easy);
        simpl in h;
        destruct m; try (rewrite is_positive_Bsign; auto);
          rewrite is_negative_Bsign; auto.

    + destruct H4.
      unfold binary_overflow in H4.
      change (Bplus m x y) with r in H4.
      destruct H2 as [H2|H2]; rewrite H2 in H4; simpl in H4;
        destruct overflow_to_inf in H4; easy.

    + apply Rnot_lt_le; assumption.
Qed.

Lemma no_overflow_or_not: forall m x, no_overflow m x \/ ~ no_overflow m x.
Proof.
  intros m x.
  rewrite no_overflow_Rabs_round_emax.
  destruct (Rlt_dec (Rabs (round m x)) (bpow radix2 emax));[left|right]; assumption.
Qed.

Lemma add_finite_rev_n' : forall (m:mode) (x:t) (y:t),
    is_finite (add m x y) ->
    (no_overflow m ((to_real x) + (to_real y))%R
     /\ to_real (add m x y) = round m ((to_real x) + (to_real y))%R)
    \/ to_real (add m x y) = max_real \/ to_real (add m x y) =-  max_real .
Proof.
intros m x y h1.
destruct (add_finite_rev m x y h1).

destruct (no_overflow_or_not m (to_real x + to_real y));[left|right].

split; [auto|apply add_finite; easy].
destruct (add_special m x y) as (_,(_,(_,(_,(_,(h,_)))))).
assert (is_finite x /\ is_finite y /\ ~ no_overflow m (to_real x + to_real y)) by auto.
apply h in H2; clear h.
destruct H2.
destruct (add m x y); try destruct s; destruct m; simpl in *; try easy;
  try (destruct H3; destruct H4; now auto);
  destruct H3, H3; auto.
Qed.

(* Why3 goal *)
Lemma sub_special :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t),
  let r := sub m x y in
  (is_nan x \/ is_nan y -> is_nan r) /\
  (is_finite x /\ is_infinite y -> is_infinite r /\ diff_sign r y) /\
  (is_infinite x /\ is_finite y -> is_infinite r /\ same_sign r x) /\
  (is_infinite x /\ is_infinite y /\ same_sign x y -> is_nan r) /\
  (is_infinite x /\ is_infinite y /\ diff_sign x y ->
   is_infinite r /\ same_sign r x) /\
  (is_finite x /\
   is_finite y /\ ~ no_overflow m ((to_real x) - (to_real y))%R ->
   same_sign_real r ((to_real x) - (to_real y))%R /\ overflow_value m r) /\
  (is_finite x /\ is_finite y ->
   (diff_sign x y -> same_sign r x) /\
   (~ diff_sign x y -> sign_zero_result m r)).
Proof.
  intros m x y r.
  unfold same_sign, diff_sign, same_sign, same_sign_real.
  split;[intro h|split;[intros (h,h1)|split;[intros (h,h1)|split;[intros (h,(h1,h2))|split;[intros (h,(h1,h2))|split;[intros (h,(h1,h2))|split;[intro h|intro h]]]]]]].
  - destruct x, y; try easy; destruct s, s0; destruct h; easy.
  - destruct x, y; try easy; destruct s, s0; auto; easy.
  - destruct x, y; try easy; destruct s, s0; auto; easy.
  - destruct x, y; try easy; destruct s, s0; destruct h2 as [(h2,h3)|(h2,h3)]; auto; easy.
  - destruct x, y; try easy; destruct s, s0; destruct h2 as [(h2,h3)|(h2,h3)]; auto; easy.
  - rewrite no_overflow_Rabs_round_max_real, Rabs_round_max_real_emax in h2.
    apply Rnot_lt_le in h2.
    pose proof (Bminus_correct sb emax Hsb' Hemax' m x y h h1).
    rewrite Rlt_bool_false in H by auto.
    destruct H.
    split.

    + destruct x, y; try easy.
      * destruct s, s0, m; simpl in H; easy.
      * rewrite B754_zero_to_real at 1 2.
        rewrite Rminus_0_l.
        rewrite <-(@B754_zero_to_real false) at 1 2.
        destruct (neg_finite (B754_finite s0 m0 e e0)) as (_,h3); auto.
        rewrite <-h3.
        destruct s0;[left;split;[easy|]|right;split;[easy|]]; apply lt_finite; easy.
      * rewrite B754_zero_to_real at 1 2.
        rewrite Rminus_0_r.
        rewrite <-(@B754_zero_to_real false) at 1 2.
        destruct s;[right;split;[easy|]|left;split;[easy|]]; apply lt_finite; easy.
      * change (Bminus m (B754_finite s m0 e e0) (B754_finite s0 m1 e1 e2)) with r in H.
        pose proof (sign_FF_overflow m (Bsign (B754_finite s m0 e e0))).
        rewrite <-H in H1.
        rewrite sign_FF_B2FF in H1.
        simpl Bsign at 2 in H1.
        assert (~is_nan r).
        { simpl binary_overflow in H.
          unfold binary_overflow in H.
          destruct overflow_to_inf in H;
            destruct r; try easy;
              destruct n; easy. }

        simpl in H0.
        apply Bool.negb_sym in H0. {

        destruct s; simpl in H0;rewrite H0 in *;[right|left];split.

        - rewrite <-is_negative_Bsign in H1; auto.
        - assert (to_real (B754_finite true m0 e e0) < 0) by
              (apply non_zero_negative_to_real; easy).
          assert (0 < to_real (B754_finite false m1 e1 e2)) by
              (apply non_zero_positive_to_real; easy).
          lra.
        - rewrite <-is_positive_Bsign in H1; auto.
        - assert (0 < to_real (B754_finite false m0 e e0)) by
              (apply non_zero_positive_to_real; easy).
          assert (to_real (B754_finite true m1 e1 e2) < 0) by
              (apply non_zero_negative_to_real; easy).
          lra. }

    + change (Bminus m x y) with r in H.
      assert (H':=H).
      apply (f_equal sign_SF) in H'.
      rewrite sign_FF_B2FF, sign_FF_overflow in H'.
      destruct m; simpl;
        unfold binary_overflow in H;
        simpl in H.
      * destruct r; try easy; destruct n; easy.
      * destruct r; try easy; destruct n; easy.
      * assert (Bsign x = true \/ Bsign x = false) by
            (destruct x ; try destruct s; simpl; auto). {
        destruct H1; rewrite H1 in H', H0, H; simpl in H.
        - split.
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign, H'; easy.
          intro; split.
          destruct r; try easy; destruct n; easy.
          replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H.
          + unfold to_real. rewrite <-min_real_is_F2R, <- SF2R_B2SF, H; auto.
          + rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto.
            now apply Pos.pow_gt_1.
        - split.
          destruct r; easy.
          intro.
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign in H2; auto; easy. }
      * assert (Bsign x = true \/ Bsign x = false) by
            (destruct x ; try destruct s; simpl; auto). {
        destruct H1; rewrite H1 in H', H0, H; simpl in H.
        - split.
          intro.
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign in H2; auto. rewrite H' in H2; easy.
          destruct r; try easy; destruct n; easy.
        - split.
          intro; split.
          destruct r; easy.
          replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H.
          + unfold to_real. rewrite <-max_real_is_F2R, <- SF2R_B2SF, H; auto.
          + rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto.
              now apply Pos.pow_gt_1.
          + assert (~is_nan r) by
                (destruct r; try easy; destruct n; easy).
            rewrite is_positive_Bsign; easy. }
      * assert (Bsign x = true \/ Bsign x = false) by
            (destruct x ; try destruct s; simpl; auto).
        assert (~is_nan r) by
            (destruct H1, r; try easy; destruct n; easy).
        rewrite is_positive_Bsign; auto. {
        destruct H1; rewrite H1 in H', H0, H; simpl in H.
        - split.
          rewrite H'; easy.
          intro; split.
          destruct r; try easy; destruct n; easy.
          replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H.
          + unfold to_real. rewrite <-min_real_is_F2R, <- SF2R_B2SF, H; auto.
          + rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto.
            now apply Pos.pow_gt_1.
        - split.
          + intro; split.
            destruct r; try easy; destruct n; easy.
            replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H.
            * unfold to_real. rewrite <-max_real_is_F2R, <- SF2R_B2SF, H; auto.
            *  rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto.
               now apply Pos.pow_gt_1.
          + easy. }
  - destruct H.
    pose proof (Bminus_correct sb emax Hsb' Hemax' m x y H H0).
    destruct (Rlt_le_dec (Rabs (round m (to_real x - to_real y))) (bpow radix2 emax)).
    + rewrite Rlt_bool_true in H1; auto.
      destruct H1 as (h1,(h2,h3)).
      change (Bminus m x y) with r in h1, h2, h3.
      assert (~is_nan r) by (destruct r; easy).
      destruct h as [(h,h')|(h,h')];[left|right];split;auto.
      * rewrite is_positive_Bsign; auto.
        destruct y; try destruct s; destruct x; try destruct s; try easy.
        rewrite Rcompare_Gt in h3; auto.
        assert (B2R (B754_finite true m0 e e0) < 0) by
            (apply non_zero_negative_to_real; easy).
        assert (0 < B2R (B754_finite false m1 e1 e2)) by
            (apply non_zero_positive_to_real; easy).
        lra.
      * rewrite is_negative_Bsign; auto.
        destruct y; try destruct s; destruct x; try destruct s; try easy.
        rewrite Rcompare_Lt in h3; auto.
        assert (0 < B2R (B754_finite false m0 e e0)) by
            (apply non_zero_positive_to_real; easy).
        assert (B2R (B754_finite true m1 e1 e2) < 0) by
            (apply non_zero_negative_to_real; easy).
        lra.
    + rewrite Rlt_bool_false in H1; auto.
      destruct H1 as (h1,h2).
      change (Bminus m x y) with r in h1.
      destruct (is_nan_dec r).
      destruct x; try destruct s; destruct y; try destruct s; try easy; destruct m;
        unfold binary_overflow in h1; simpl in h1;
          destruct r; try easy; destruct n; easy.

      rewrite is_positive_Bsign; auto.
      rewrite is_negative_Bsign; auto.
      apply (f_equal sign_SF) in h1.
      rewrite sign_FF_B2FF, sign_FF_overflow in h1.
      assert (~is_nan x) by (destruct x; easy).
      assert (~is_nan y) by (destruct y; easy).
      rewrite is_positive_Bsign in h,h; auto.
      rewrite is_negative_Bsign in h,h; auto.
      destruct h as [(h,h')|(h,h')];rewrite h in h1, h2;[left|right];split;auto.
      rewrite is_positive_Bsign; auto.
      rewrite is_negative_Bsign; auto.
  - intuition.
    unfold sign_zero_result; intro.
    unfold is_zero in H2.
    rewrite eq_zero_iff in H2.
    pose proof (Bminus_correct sb emax Hsb' Hemax' m x y H0 H1).
    destruct (Rlt_dec (Rabs (round m (to_real x - to_real y))) (bpow radix2 emax)) as [r0|r0];
      [rewrite Rlt_bool_true in H4; auto; clear r0|
       rewrite Rlt_bool_false in H4].
    + destruct H4 as (h1,(h2,h)).

      assert (to_real x - to_real y = 0).
      { cut (not (to_real x - to_real y <> 0)).
        lra.
        intros H9.
        apply (round_plus_neq_0 radix2 fexp (round_mode m)) in H9.
        apply H9.
        destruct H2 as [H2|H2]; apply (f_equal to_real) in H2.
        rewrite zeroF_to_real in H2.
        rewrite <-H2; auto.
        assert (is_finite zeroF) as zero_is_finite by easy.
        destruct (neg_finite zeroF zero_is_finite).
        rewrite H5, zeroF_to_real, Ropp_0 in H2.
        rewrite <-H2; auto.
        apply generic_format_B2R.
        destruct (neg_finite y) as (_,h3); auto; rewrite <-h3.
        apply generic_format_B2R. }

      rewrite Rcompare_Eq in h; auto.
      change (Bminus m x y) with r in h.

      assert (~is_nan r) by (destruct H2, r; easy).

      destruct x ; try destruct s; destruct y ; try destruct s;
        try (simpl in H; contradict H; now auto);
        try (destruct m; simpl in r; easy);
        simpl in h;
        destruct m; try (rewrite is_positive_Bsign; auto);
          rewrite is_negative_Bsign; auto.

    + destruct H4.
      unfold binary_overflow in H4.
      change (Bminus m x y) with r in H4.
      destruct H2 as [H2|H2]; rewrite H2 in H4; simpl in H4;
        destruct overflow_to_inf in H4; easy.

    + apply Rnot_lt_le; assumption.
Qed.

Lemma sub_finite_rev_n' : forall (m:mode) (x:t) (y:t),
    is_finite (sub m x y) ->
    (no_overflow m ((to_real x) - (to_real y))%R
     /\ to_real (sub m x y) = round m ((to_real x) - (to_real y))%R)
    \/ to_real (sub m x y) = max_real \/ to_real (sub m x y) =-  max_real .
Proof.
intros m x y h1.
destruct (sub_finite_rev m x y h1).
destruct (no_overflow_or_not m (to_real x - to_real y));[left|right].
split; [auto|apply sub_finite; easy].
destruct (sub_special m x y) as (_,(_,(_,(_,(_,(h,_)))))).
assert (is_finite x /\ is_finite y /\ ~ no_overflow m (to_real x - to_real y)) by auto.
apply h in H2; clear h.
destruct H2.
destruct (sub m x y); try destruct s; destruct m; simpl in *; try easy;
  try (destruct H3; destruct H4; now auto);
  destruct H3, H3; auto.
Qed.

(* Why3 goal *)
Lemma mul_special :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t),
  let r := mul m x y in
  (is_nan x \/ is_nan y -> is_nan r) /\
  (is_zero x /\ is_infinite y -> is_nan r) /\
  (is_finite x /\ is_infinite y /\ ~ is_zero x -> is_infinite r) /\
  (is_infinite x /\ is_zero y -> is_nan r) /\
  (is_infinite x /\ is_finite y /\ ~ is_zero y -> is_infinite r) /\
  (is_infinite x /\ is_infinite y -> is_infinite r) /\
  (is_finite x /\
   is_finite y /\ ~ no_overflow m ((to_real x) * (to_real y))%R ->
   overflow_value m r) /\
  (~ is_nan r -> product_sign r x y).
Proof.
  intros m x y r.
  unfold product_sign, same_sign, diff_sign.
  intuition.
  - destruct x; easy.
  - destruct x, y; easy.
  - destruct x, y; try destruct s; easy.
  - destruct x, y; try destruct s; try easy; contradict H2; easy.
  - destruct x, y; try destruct s0; easy.
  - destruct x, y; try destruct s0; try easy; contradict H2; easy.
  - destruct x, y; easy.
  - rewrite no_overflow_Rabs_round_max_real, Rabs_round_max_real_emax in H2.
    apply Rnot_lt_le in H2.
    pose proof (Bmult_correct sb emax Hsb' Hemax' m x y).
    rewrite Rlt_bool_false in H1 by auto.
    change (Bmult m x y) with r in H1.
    assert (H1':=H1).
    apply (f_equal sign_SF) in H1'.
    rewrite sign_FF_B2FF, sign_FF_overflow in H1'.
    destruct m; simpl;
      unfold binary_overflow in H1;
      simpl in H1.
    * destruct r; try easy; destruct n; easy.
    * destruct r; try easy; destruct n; easy.
    * assert (Bsign x = true \/ Bsign x = false) by
          (destruct x ; try destruct s; simpl; auto).
      assert (Bsign y = true \/ Bsign y = false) by
          (destruct y; try destruct s; simpl; auto). {
        destruct H3, H4; rewrite H3, H4 in H1', H1; simpl in H1, H1'.
        - split.
          destruct r; easy.
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign, H1'; intro h; contradict h; easy.
        - split.
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign, H1'; intro h; contradict h; easy.
          intro; split.
          destruct r; try easy; destruct n; easy.
          replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H1.
          + unfold to_real. rewrite <-min_real_is_F2R, <- SF2R_B2SF, H1; auto.
          + rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto.
            now apply Pos.pow_gt_1.
        - split.
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign, H1'; intro h; contradict h; easy.
          intro; split.
          destruct r; try easy; destruct n; easy.
          replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H1.
          + unfold to_real. rewrite <-min_real_is_F2R, <- SF2R_B2SF, H1; auto.
          + rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto.
            now apply Pos.pow_gt_1.
        - split.
          destruct r; easy.
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign, H1'; intro h; contradict h; easy. }
    * assert (Bsign x = true \/ Bsign x = false) by
          (destruct x ; try destruct s; simpl; auto).
      assert (Bsign y = true \/ Bsign y = false) by
          (destruct y; try destruct s; simpl; auto). {
      destruct H3, H4; rewrite H3, H4 in H1', H1; simpl in H1, H1'.
      - split.
        { intro; split.
          destruct r; try easy; destruct n; easy.
          replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H1.
          + unfold to_real. rewrite <-max_real_is_F2R, <- SF2R_B2SF, H1; auto.
          + rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto.
            now apply Pos.pow_gt_1. }
        assert (~is_nan r) by
            (destruct r; try easy; destruct n; easy).
        rewrite is_positive_Bsign, H1'; intro h; contradict h; easy.
      - split.
        assert (~is_nan r) by
            (destruct r; try easy; destruct n; easy).
        rewrite is_positive_Bsign, H1'; intro h; contradict h; easy.
        destruct r; try easy; destruct n; easy.
      - split.
        assert (~is_nan r) by
            (destruct r; try easy; destruct n; easy).
        rewrite is_positive_Bsign, H1'; intro h; contradict h; easy.
        destruct r; try easy; destruct n; easy.
      - split.
        { intro; split.
          destruct r; try easy; destruct n; easy.
          replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H1.
          + unfold to_real. rewrite <-max_real_is_F2R, <- SF2R_B2SF, H1; auto.
          + rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto.
            now apply Pos.pow_gt_1. }
        assert (~is_nan r) by
            (destruct r; try easy; destruct n; easy).
        rewrite is_positive_Bsign, H1'; intro h; contradict h; easy. }
    * assert (Bsign x = true \/ Bsign x = false) by
          (destruct x ; try destruct s; simpl; auto).
      assert (Bsign y = true \/ Bsign y = false) by
          (destruct y; try destruct s; simpl; auto).
      replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H1.
      { unfold to_real. rewrite <-min_real_is_F2R,<-max_real_is_F2R, <- SF2R_B2SF, H1; auto.
        destruct H3, H4; rewrite H3, H4 in *; simpl in *.
        - split.
          intro; split; [destruct r; easy|auto].
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign, H1'; intro h; contradict h; easy.
        - split.
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign, H1'; intro h; contradict h; easy.
          intro; split; [destruct r; try easy; destruct n; easy|auto].
        - split.
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign, H1'; intro h; contradict h; easy.
          intro; split; [destruct r; try easy; destruct n; easy|auto].
        - split.
          intro; split; [destruct r; easy|auto].
          assert (~is_nan r) by
              (destruct r; try easy; destruct n; easy).
          rewrite is_positive_Bsign, H1'; intro h; contradict h; easy. }
      rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto.
      now apply Pos.pow_gt_1.
  - pose proof (Bmult_correct sb emax Hsb' Hemax' m x y).
    destruct (Rlt_le_dec (Rabs (round m (to_real x * to_real y))) (bpow radix2 emax));
    [rewrite Rlt_bool_true in H1; auto| rewrite Rlt_bool_false in H1; auto].
    + destruct H1 as (h1, (h2, h3)).
      rewrite is_positive_Bsign; auto.
      unfold r, mul, Hsb''.
      rewrite h3.
      destruct x; try destruct s; destruct y; try destruct s; easy.
      now apply Bool.not_true_is_false.
    + apply (f_equal sign_SF) in H1.
      rewrite sign_FF_B2FF, sign_FF_overflow in H1.
      rewrite is_positive_Bsign; auto.
      destruct x; try destruct s; destruct y; try destruct s; easy.
  - pose proof (Bmult_correct sb emax Hsb' Hemax' m x y).
    destruct (Rlt_le_dec (Rabs (round m (to_real x * to_real y))) (bpow radix2 emax));
    [rewrite Rlt_bool_true in H1; auto| rewrite Rlt_bool_false in H1; auto].
    + destruct H1 as (h1, (h2, h3)).
      rewrite is_positive_Bsign; auto.
      unfold r, mul, Hsb''.
      rewrite h3.
      destruct x; try destruct s; destruct y; try destruct s; easy.
      now apply Bool.not_true_is_false.
    + apply (f_equal sign_SF) in H1.
      rewrite sign_FF_B2FF, sign_FF_overflow in H1.
      rewrite is_positive_Bsign; auto.
      destruct x; try destruct s; destruct y; try destruct s; easy.
  - pose proof (Bmult_correct sb emax Hsb' Hemax' m x y).
    destruct (Rlt_le_dec (Rabs (round m (to_real x * to_real y))) (bpow radix2 emax));
    [rewrite Rlt_bool_true in H1; auto| rewrite Rlt_bool_false in H1; auto].
    + destruct H1 as (h1, (h2, h3)).
      rewrite is_negative_Bsign; auto.
      unfold r, mul, Hsb''.
      rewrite h3.
      destruct x; try destruct s; destruct y; try destruct s; auto.
      now apply Bool.not_true_is_false.
    + apply (f_equal sign_SF) in H1.
      rewrite sign_FF_B2FF, sign_FF_overflow in H1.
      rewrite is_negative_Bsign; auto.
      destruct x; try destruct s; destruct y; try destruct s; auto.
  - pose proof (Bmult_correct sb emax Hsb' Hemax' m x y).
    destruct (Rlt_le_dec (Rabs (round m (to_real x * to_real y))) (bpow radix2 emax));
    [rewrite Rlt_bool_true in H1; auto| rewrite Rlt_bool_false in H1; auto].
    + destruct H1 as (h1, (h2, h3)).
      rewrite is_negative_Bsign; auto.
      unfold r, mul, Hsb''.
      rewrite h3.
      destruct x; try destruct s; destruct y; try destruct s; auto.
      now apply Bool.not_true_is_false.
    + apply (f_equal sign_SF) in H1.
      rewrite sign_FF_B2FF, sign_FF_overflow in H1.
      rewrite is_negative_Bsign; auto.
      destruct x; try destruct s; destruct y; try destruct s; auto.
Qed.

Lemma mul_finite_rev_n' : forall (m:mode) (x:t) (y:t),
    is_finite (mul m x y) ->
    (no_overflow m ((to_real x) * (to_real y))%R
     /\ to_real (mul m x y) = round m ((to_real x) * (to_real y))%R)
    \/ to_real (mul m x y) = max_real \/ to_real (mul m x y) =-  max_real .
Proof.
intros m x y h1.
destruct (mul_finite_rev m x y h1).
destruct (no_overflow_or_not m (to_real x * to_real y));[left|right].
split; [auto|apply mul_finite; easy].
destruct (mul_special m x y) as (_,(_,(_,(_,(_,(_,(h,_))))))).
assert (is_finite x /\ is_finite y /\ ~ no_overflow m (to_real x * to_real y)) by auto.
apply h in H2; clear h.
destruct (mul m x y); try destruct s; destruct m; simpl in *; try easy;
  try (destruct H2; destruct H3; now auto);
  destruct H2, H2; auto.
Qed.

(* Why3 goal *)
Lemma div_special :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t),
  let r := div m x y in
  (is_nan x \/ is_nan y -> is_nan r) /\
  (is_finite x /\ is_infinite y -> is_zero r) /\
  (is_infinite x /\ is_finite y -> is_infinite r) /\
  (is_infinite x /\ is_infinite y -> is_nan r) /\
  (is_finite x /\
   is_finite y /\
   ~ is_zero y /\ ~ no_overflow m ((to_real x) / (to_real y))%R ->
   overflow_value m r) /\
  (is_finite x /\ is_zero y /\ ~ is_zero x -> is_infinite r) /\
  (is_zero x /\ is_zero y -> is_nan r) /\ (~ is_nan r -> product_sign r x y).
Proof.
  intros m x y r.
  unfold product_sign, same_sign, diff_sign.
  intuition.
  - destruct x; easy.
  - destruct x, y; easy.
  - destruct x, y; try destruct s; easy.
  - destruct x, y; try destruct s; try easy; contradict H2; easy.
  - destruct x, y; try destruct s0; easy.
  - assert (to_real y <> 0) by (rewrite zero_to_real in H1; auto).
    pose proof (Bdiv_correct sb emax Hsb' Hemax' m x y H2).
    rewrite Rlt_bool_false in H4.
    + unfold binary_overflow in H4.
      change (Bdiv m x y) with r in H4; auto.
      destruct m; simpl in *.
      * now destruct r.
      * now destruct r.
      * destruct (xorb (Bsign x) (Bsign y)); simpl in H4. {
          split; intro.
          - destruct r; try destruct s; easy.
          - split; [destruct r; try easy; destruct b, n in H4; easy|].
            apply (f_equal (SF2R radix2)) in H4.
            rewrite SF2R_B2SF in H4.
            simpl in H4.
            replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H4 by
                (rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto;
                 now apply Pos.pow_gt_1).
            rewrite <-min_real_is_F2R; assumption. }
        split; intro; [destruct r; easy|].
        destruct r; try easy.
        destruct s; try easy.
        simpl in H5; contradict H5; auto.
      * destruct (xorb (Bsign x) (Bsign y)); simpl in H4. {
        split; intro.
        - destruct r; try destruct s; easy.
        - now destruct r. }
        { split; intro.
          + split;[destruct r; easy|].
            apply (f_equal (SF2R radix2)) in H4.
            rewrite SF2R_B2SF in H4.
            simpl in H4.
            replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H4 by
                (rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto;
                 now apply Pos.pow_gt_1).
            rewrite <-max_real_is_F2R; assumption.
          + destruct r; try easy; try (destruct n; easy).
            destruct s; try easy.
            simpl in H5; contradict H5; auto. }
      * { destruct (xorb (Bsign x) (Bsign y)); simpl in H4;
        split; intro.
          - destruct r; try destruct s; easy.
          - split;[destruct r; try destruct s; try easy; destruct n; easy|].
            apply (f_equal (SF2R radix2)) in H4.
            rewrite SF2R_B2SF in H4.
            simpl in H4.
            replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H4 by
                (rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto;
                 now apply Pos.pow_gt_1).
            rewrite <-min_real_is_F2R; assumption.
          - split; [destruct r; try easy| ].
            apply (f_equal (SF2R radix2)) in H4.
            rewrite SF2R_B2SF in H4.
            simpl in H4.
            replace (Z.pow_pos 2 sb_pos - 1)%Z with (Z.pos (2 ^ sb_pos - 1)) in H4 by
                (rewrite Pos2Z.inj_sub, Pos2Z.inj_pow_pos; auto;
                 now apply Pos.pow_gt_1).
            rewrite <-max_real_is_F2R; assumption.
          - contradict H5.
            destruct r; try destruct s; easy. }
    + clear H4.
      rewrite no_overflow_Rabs_round_emax in H3.
      apply Rge_le, Rnot_lt_ge; assumption.
  - destruct x, y; try easy.
    rewrite is_zero_B754_zero in H2; destruct H2; exists s; reflexivity.
    rewrite is_zero_B754_zero in H2; destruct H2; exists s; reflexivity.
    rewrite is_zero_B754_zero in H; destruct H; inversion H.
    rewrite is_zero_B754_zero in H; destruct H; inversion H.
  - rewrite is_zero_B754_zero in H0; destruct H0.
    rewrite is_zero_B754_zero in H1; destruct H1.
    destruct x, y; easy.
  - destruct x ; try destruct s; destruct y ; try destruct s; try easy.
    now elim H.
    now elim H.
    set (x:=B754_finite false m0 e e0);
      set (y:=B754_finite false m1 e1 e2); fold x y in r, H0, H2.
    assert (to_real y <> 0).
    { assert (0 < to_real y) by
          (apply non_zero_positive_to_real; easy).
      apply not_eq_sym, Rlt_not_eq; lra. }
    pose proof (Bdiv_correct sb emax Hsb' Hemax' m x y H1).
    destruct (Rlt_le_dec (Rabs (round m (to_real x / to_real y))) (bpow radix2 emax));
      [rewrite Rlt_bool_true in H3|rewrite Rlt_bool_false in H3];auto.
    + destruct H3 as (_,(_,h)).
      rewrite is_positive_Bsign; auto.
      unfold r, div, Hsb''.
      rewrite h.
      easy.
      now apply Bool.not_true_is_false.
    + apply (f_equal sign_SF) in H3.
      rewrite sign_FF_B2FF, sign_FF_overflow in H3.
      rewrite is_positive_Bsign; auto.
  - destruct x ; try destruct s; destruct y ; try destruct s; try easy.
    now elim H.
    now elim H.
    set (x:=B754_finite true m0 e e0);
      set (y:=B754_finite true m1 e1 e2); fold x y in r, H0, H2.
    assert (to_real y <> 0).
    { assert (to_real y < 0) by
          (apply non_zero_negative_to_real; easy).
      apply Rlt_not_eq; lra. }
    pose proof (Bdiv_correct sb emax Hsb' Hemax' m x y H1).
    destruct (Rlt_le_dec (Rabs (round m (to_real x / to_real y))) (bpow radix2 emax));
      [rewrite Rlt_bool_true in H3|rewrite Rlt_bool_false in H3];auto.
    + destruct H3 as (_,(_,h)).
      rewrite is_positive_Bsign; auto.
      unfold r, div, Hsb''.
      rewrite h.
      easy.
      now apply Bool.not_true_is_false.
    + apply (f_equal sign_SF) in H3.
      rewrite sign_FF_B2FF, sign_FF_overflow in H3.
      rewrite is_positive_Bsign; auto.
  - destruct x ; try destruct s; destruct y ; try destruct s; try easy.
    now elim H.
    now elim H.
    set (x:=B754_finite false m0 e e0);
      set (y:=B754_finite true m1 e1 e2); fold x y in r, H0, H2.
    assert (to_real y <> 0).
    { assert (to_real y < 0) by
          (apply non_zero_negative_to_real; easy).
      apply Rlt_not_eq; lra. }
    pose proof (Bdiv_correct sb emax Hsb' Hemax' m x y H1).
    destruct (Rlt_le_dec (Rabs (round m (to_real x / to_real y))) (bpow radix2 emax));
      [rewrite Rlt_bool_true in H3|rewrite Rlt_bool_false in H3];auto.
    + destruct H3 as (_,(_,h)).
      rewrite is_negative_Bsign; auto.
      unfold r, div, Hsb''.
      rewrite h.
      easy.
      now apply Bool.not_true_is_false.
    + apply (f_equal sign_SF) in H3.
      rewrite sign_FF_B2FF, sign_FF_overflow in H3.
      rewrite is_negative_Bsign; auto.
  - destruct x; try destruct s; destruct y; try destruct s; try easy.
    now elim H.
    now elim H.
    set (x:=B754_finite true m0 e e0);
      set (y:=B754_finite false m1 e1 e2); fold x y in r, H0, H2.
    assert (to_real y <> 0).
    { assert (0 < to_real y) by
          (apply non_zero_positive_to_real; easy).
      apply not_eq_sym, Rlt_not_eq; lra. }
    pose proof (Bdiv_correct sb emax Hsb' Hemax' m x y H1).
    destruct (Rlt_le_dec (Rabs (round m (to_real x / to_real y))) (bpow radix2 emax));
      [rewrite Rlt_bool_true in H3|rewrite Rlt_bool_false in H3];auto.
    + destruct H3 as (_,(_,h)).
      rewrite is_negative_Bsign; auto.
      unfold r, div, Hsb''.
      rewrite h.
      easy.
      now apply Bool.not_true_is_false.
    + apply (f_equal sign_SF) in H3.
      rewrite sign_FF_B2FF, sign_FF_overflow in H3.
      rewrite is_negative_Bsign; auto.
Qed.

(* Why3 goal *)
Lemma neg_special :
  forall (x:t),
  (is_nan x -> is_nan (neg x)) /\
  (is_infinite x -> is_infinite (neg x)) /\
  (~ is_nan x -> diff_sign x (neg x)).
Proof.
  intros x.
  split; [|split]; intro.
  - destruct x; easy.
  - destruct x; easy.
  - unfold diff_sign.
    destruct x.
    destruct s;[right|left]; easy.
    destruct s;[right|left]; easy.
    contradict H; easy.
    destruct s;[right|left]; easy.
Qed.

(* Why3 goal *)
Lemma abs_special :
  forall (x:t),
  (is_nan x -> is_nan (abs x)) /\
  (is_infinite x -> is_infinite (abs x)) /\
  (~ is_nan x -> is_positive (abs x)).
Proof.
  intros x.
  split;[|split];intro.
  - destruct x; easy.
  - destruct x; easy.
  - destruct x; try easy.
    contradict H; easy.
Qed.

(* add to theory ? *)
Lemma abs_le_inv: forall {x y}, le (abs x) y -> le (neg y) x /\ le x y.
Proof.
  intros x y.
  destruct (Finite_Infinite_Nan_dec y) as [[hy|hy]|hy].
  + destruct (Finite_Infinite_Nan_dec x) as [[hx|hx]|hx].

    * pose proof (is_finite_abs _ hx).
      destruct (neg_finite _ hy).
      rewrite (le_to_real (abs x) y) by auto.
      rewrite (le_to_real (neg y) x) by auto.
      rewrite le_to_real by auto.
      rewrite H1 by auto.
      destruct (abs_finite _ hx) as (_,(u,_)).
      rewrite u.
      apply Rabs_le_inv.

    * intros a.
      pose proof (abs_special x) as (_,(b,_)); pose proof (b hx); clear b.
      destruct (le_special _ _ a) as [H1|[H1|H1]].
      - destruct x; easy.
      - unfold is_minus_infinity in H1.
        destruct H1, H1, x, y; try easy; destruct b0, b1; easy.
      - destruct y; unfold is_plus_infinity in H1; easy.

    * intros a.
      pose proof (abs_special x) as (b,_); pose proof (b hx); clear b.
      destruct (le_special _ _ a) as [H1|[H1|H1]];
        unfold is_minus_infinity, is_not_nan in H1;
        destruct (abs x), H1; easy.

  + intros a.

    destruct (Finite_Infinite_Nan_dec x) as [[hx|hx]|hx].
    * pose proof (is_finite_abs _ hx).
      destruct (le_special _ _ a) as [H1|[H1|H1]].
      - destruct y; easy.
      - unfold is_minus_infinity in H1; destruct x; easy.
      - destruct y, H1; try easy.
        unfold is_plus_infinity in H1; destruct s; try easy.
        destruct x ; try destruct s; split; easy.
    * unfold Bcompare.
      destruct x, y; try easy; destruct s, s0; simpl; split; auto; easy.
    * now destruct x.
  + intros a.
    destruct y; unfold le, Bcompare in a; try easy.
    destruct x; try destruct s0; split; easy.
Qed.

(* Why3 goal *)
Lemma fma_special :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t) (z:t),
  let r := fma m x y z in
  (is_nan x \/ is_nan y \/ is_nan z -> is_nan r) /\
  (is_zero x /\ is_infinite y -> is_nan r) /\
  (is_infinite x /\ is_zero y -> is_nan r) /\
  (is_finite x /\ ~ is_zero x /\ is_infinite y /\ is_finite z ->
   is_infinite r /\ product_sign r x y) /\
  (is_finite x /\ ~ is_zero x /\ is_infinite y /\ is_infinite z ->
   (product_sign z x y -> is_infinite r /\ same_sign r z) /\
   (~ product_sign z x y -> is_nan r)) /\
  (is_infinite x /\ is_finite y /\ ~ is_zero y /\ is_finite z ->
   is_infinite r /\ product_sign r x y) /\
  (is_infinite x /\ is_finite y /\ ~ is_zero y /\ is_infinite z ->
   (product_sign z x y -> is_infinite r /\ same_sign r z) /\
   (~ product_sign z x y -> is_nan r)) /\
  (is_infinite x /\ is_infinite y /\ is_finite z ->
   is_infinite r /\ product_sign r x y) /\
  (is_finite x /\ is_finite y /\ is_infinite z ->
   is_infinite r /\ same_sign r z) /\
  (is_infinite x /\ is_infinite y /\ is_infinite z ->
   (product_sign z x y -> is_infinite r /\ same_sign r z) /\
   (~ product_sign z x y -> is_nan r)) /\
  (is_finite x /\
   is_finite y /\
   is_finite z /\
   ~ no_overflow m (((to_real x) * (to_real y))%R + (to_real z))%R ->
   same_sign_real r (((to_real x) * (to_real y))%R + (to_real z))%R /\
   overflow_value m r) /\
  (is_finite x /\ is_finite y /\ is_finite z ->
   (product_sign z x y -> same_sign r z) /\
   (~ product_sign z x y ->
    ((((to_real x) * (to_real y))%R + (to_real z))%R = 0%R) ->
    ((m = ieee_float.RoundingMode.RTN) -> is_negative r) /\
    (~ (m = ieee_float.RoundingMode.RTN) -> is_positive r))).
Proof.
intros m x y z r.
Admitted.

Lemma fma_finite_rev_n' : forall (m:mode) (x:t) (y:t) (z:t),
    is_finite (fma m x y z) ->
    (no_overflow m (to_real x * to_real y + to_real z)%R
     /\ to_real (fma m x y z) = round m (to_real x * to_real y + to_real z)%R)
    \/ to_real (fma m x y z) = max_real \/ to_real (fma m x y z) =-  max_real .
Proof.
intros m x y z h1.
destruct (fma_finite_rev m x y z h1) as (H,(H0,H1)).

destruct (no_overflow_or_not m (to_real x * to_real y + to_real z));[left|right].

split; [auto|apply fma_finite; easy].
destruct (fma_special m x y z) as (_,(_,(_,(_,(_,(_,(_,(_,(_,(_,(h,_))))))))))).
assert (is_finite x /\ is_finite y /\ is_finite z /\ ~ no_overflow m (to_real x * to_real y + to_real z)) by auto.
apply h in H3; clear h.
destruct (fma m x y z); try destruct s; destruct m; simpl in *; try easy;
  try (destruct H3; destruct H4; destruct H4; now auto);
  destruct H3; destruct H4; destruct H5; auto.
Qed.

(* Why3 goal *)
Lemma sqrt_special :
  forall (m:ieee_float.RoundingMode.mode) (x:t),
  let r := sqrt m x in
  (is_nan x -> is_nan r) /\
  (is_plus_infinity x -> is_plus_infinity r) /\
  (is_minus_infinity x -> is_nan r) /\
  (is_finite x /\ ((to_real x) < 0%R)%R -> is_nan r) /\
  (is_zero x -> same_sign r x) /\
  (is_finite x /\ (0%R < (to_real x))%R -> is_positive r).
Proof.
  intros m x r.
  unfold sqrt in r.
  intuition.
  - destruct x; easy.
  - unfold is_plus_infinity in *.
    destruct x ; try destruct s; easy.
  - unfold is_minus_infinity in H.
    destruct x ; try destruct s; easy.
  - destruct x ; try destruct s; try easy.
    rewrite B754_zero_to_real in H1; lra.
    rewrite B754_zero_to_real in H1; lra.
    apply (to_real_negative _ H0) in H1.
    rewrite is_negative_Bsign in H1 by easy.
    easy.
  - unfold same_sign.
    rewrite is_zero_B754_zero in H; destruct H.
    destruct x; try easy.
    destruct s;[right|left];split;auto.
    simpl in r; unfold r; auto.
    simpl in r; unfold r; auto.
  - destruct (Bsqrt_correct sb emax Hsb' Hemax' m x) as (_,(h1,h2));
      fold r in h1, h2.
    destruct x; try easy.
    rewrite B754_zero_to_real in H1 at 1; lra.
    apply (to_real_positive _ H0) in H1.
    rewrite is_positive_Bsign in H1 by easy.
    simpl in H1.
    destruct s; try easy.
    assert (not (is_nan r)) by (destruct r; easy).
    rewrite (is_positive_Bsign _ H).
    apply h2.
    now apply Bool.not_true_is_false.
Qed.

Lemma in_int_range_no_overflow : forall m {i}, in_int_range i -> no_overflow m (IZR i).
Proof.
  intros m i h.
  apply Bounded_real_no_overflow.
  unfold in_int_range in h.
  unfold in_range.
  rewrite max_real_int, <- FromInt.Neg.
  pose proof pow2sb_lt_max_int.
  split; apply IZR_le; auto with zarith.
Qed.

(* Why3 goal *)
Lemma of_int_add_exact :
  forall (m:ieee_float.RoundingMode.mode) (n:ieee_float.RoundingMode.mode)
    (i:Numbers.BinNums.Z) (j:Numbers.BinNums.Z),
  in_safe_int_range i -> in_safe_int_range j ->
  in_safe_int_range (i + j)%Z ->
  eq (of_int m (i + j)%Z) (add n (of_int m i) (of_int m j)).
Proof.
  intros m n i j h1 h2 h3.
  assert (h1':= in_safe_int_range_no_overflow m h1).
  assert (h2':= in_safe_int_range_no_overflow m h2).
  assert (h3':= in_safe_int_range_no_overflow n h3).
  assert (h3'':= in_safe_int_range_no_overflow m h3).
  assert (is_finite (of_int m i)) by (apply of_int_correct; assumption).
  assert (is_finite (of_int m j)) by (apply of_int_correct; assumption).
  assert (is_finite (of_int n (i+j)%Z)) by (apply of_int_correct; assumption).
  assert (is_finite (of_int m (i+j)%Z)) by (apply of_int_correct; assumption).
  destruct (of_int_correct h1') as (f,_).
  destruct (of_int_correct h2') as (g,_).
  destruct (add_finite n (of_int m i) (of_int m j)); auto.
  simpl; rewrite f, g, Exact_rounding_for_integers, Exact_rounding_for_integers; auto.
  rewrite <-plus_IZR; assumption.
  destruct (of_int_correct h3'') as (h,_).
  rewrite to_real_eq, H4, f, g, h; auto.
  repeat rewrite Exact_rounding_for_integers; auto.
  rewrite <-plus_IZR, Exact_rounding_for_integers; auto; reflexivity.
Qed.

(* Why3 goal *)
Lemma of_int_sub_exact :
  forall (m:ieee_float.RoundingMode.mode) (n:ieee_float.RoundingMode.mode)
    (i:Numbers.BinNums.Z) (j:Numbers.BinNums.Z),
  in_safe_int_range i -> in_safe_int_range j ->
  in_safe_int_range (i - j)%Z ->
  eq (of_int m (i - j)%Z) (sub n (of_int m i) (of_int m j)).
Proof.
  intros m n i j h1 h2 h3.
  assert (h1':= in_safe_int_range_no_overflow m h1).
  assert (h2':= in_safe_int_range_no_overflow m h2).
  assert (h3':= in_safe_int_range_no_overflow n h3).
  assert (h3'':= in_safe_int_range_no_overflow m h3).
  assert (is_finite (of_int m i)) by (apply of_int_correct; assumption).
  assert (is_finite (of_int m j)) by (apply of_int_correct; assumption).
  assert (is_finite (of_int n (i-j)%Z)) by (apply of_int_correct; assumption).
  assert (is_finite (of_int m (i-j)%Z)) by (apply of_int_correct; assumption).
  destruct (of_int_correct h1') as (f,_).
  destruct (of_int_correct h2') as (g,_).
  destruct (sub_finite n (of_int m i) (of_int m j)); auto.
  simpl; rewrite f, g, Exact_rounding_for_integers, Exact_rounding_for_integers; auto.
  rewrite <-minus_IZR; assumption.
  destruct (of_int_correct h3'') as (h,_).
  rewrite to_real_eq, H4, f, g, h; auto.
  repeat rewrite Exact_rounding_for_integers; auto.
  rewrite <-minus_IZR, Exact_rounding_for_integers; auto; reflexivity.
Qed.

(* Why3 goal *)
Lemma of_int_mul_exact :
  forall (m:ieee_float.RoundingMode.mode) (n:ieee_float.RoundingMode.mode)
    (i:Numbers.BinNums.Z) (j:Numbers.BinNums.Z),
  in_safe_int_range i -> in_safe_int_range j ->
  in_safe_int_range (i * j)%Z ->
  eq (of_int m (i * j)%Z) (mul n (of_int m i) (of_int m j)).
Proof.
  intros m n i j h1 h2 h3.
  assert (h1':= in_safe_int_range_no_overflow m h1).
  assert (h2':= in_safe_int_range_no_overflow m h2).
  assert (h3':= in_safe_int_range_no_overflow n h3).
  assert (h3'':= in_safe_int_range_no_overflow m h3).
  assert (is_finite (of_int m i)) by (apply of_int_correct; assumption).
  assert (is_finite (of_int m j)) by (apply of_int_correct; assumption).
  assert (is_finite (of_int n (i*j)%Z)) by (apply of_int_correct; assumption).
  assert (is_finite (of_int m (i*j)%Z)) by (apply of_int_correct; assumption).
  destruct (of_int_correct h1') as (f,_).
  destruct (of_int_correct h2') as (g,_).
  destruct (mul_finite n (of_int m i) (of_int m j)); auto.
  simpl; rewrite f, g,
         Exact_rounding_for_integers, Exact_rounding_for_integers; auto.
  rewrite <-mult_IZR; assumption.
  destruct (of_int_correct h3'') as (h,_).
  rewrite to_real_eq, H4, f, g, h; auto.
  repeat rewrite Exact_rounding_for_integers; auto.
  rewrite <-mult_IZR, Exact_rounding_for_integers; auto; reflexivity.
Qed.

(* Why3 goal *)
Lemma Min_r : forall (x:t) (y:t), le y x -> eq (min x y) y.
Proof.
intros x y h1.
unfold min.
apply le_correct in h1.
destruct h1;
pose (Bcompare_swap _ _ y x);
rewrite H in e;
unfold min; rewrite e; simpl.
apply (eq_not_nan_refl (proj1 (lt_not_nan H))).
apply (eq_not_nan_refl (proj1 (eq_not_nan H))).
Qed.

(* Why3 goal *)
Lemma Min_l : forall (x:t) (y:t), le x y -> eq (min x y) x.
Proof.
intros x y h1.
apply le_correct in h1.
destruct h1; unfold min; rewrite H; simpl.
apply (eq_not_nan_refl (proj1 (lt_not_nan H))).
pose (Bcompare_swap _ _ x y); rewrite H in e; apply e.
Qed.

(* Why3 goal *)
Lemma Max_r : forall (x:t) (y:t), le y x -> eq (max x y) x.
Proof.
intros x y h1.
apply le_correct in h1.
destruct h1;
pose (Bcompare_swap _ _ y x);
rewrite H in e;
unfold max; rewrite e; simpl.
apply (eq_not_nan_refl (proj2 (lt_not_nan H))).
apply (eq_not_nan_refl (proj2 (eq_not_nan H))).
Qed.

(* Why3 goal *)
Lemma Max_l : forall (x:t) (y:t), le x y -> eq (max x y) y.
Proof.
intros x y h1.
apply le_correct in h1.
destruct h1; unfold max; rewrite H; simpl.
apply (eq_not_nan_refl (proj2 (lt_not_nan H))).
apply H.
Qed.

Definition is_intR: R -> Prop.
Proof.
 exact (fun x => x = IZR (Zfloor x)).
Defined.

Lemma is_intR_equiv: forall {x}, (exists i:int, x = IZR i) -> is_intR x.
Proof.
  unfold is_intR.
  intros x h; destruct h.
  rewrite H, Zfloor_IZR; reflexivity.
Qed.

Lemma is_intR_IZR: forall i, is_intR (IZR i).
Proof.
  intro i; apply is_intR_equiv; exists i; reflexivity.
Qed.

Lemma is_intR_FIX_format: forall {x}, is_intR x <-> FIX_format radix2 0%Z x.
Proof.
  intro x; split; intro.
  exists ({| Fnum := Zfloor x; Fexp := 0 |}); simpl; auto.
  unfold F2R, Fnum, Fexp; simpl.
  rewrite Rmult_1_r; assumption.
  destruct H.
  unfold F2R in H.
  rewrite H0 in H; simpl in H.
  rewrite Rmult_1_r in H.
  apply is_intR_equiv.
  exists (Fnum f); assumption.
Qed.

Lemma is_intR_round: forall {x m}, is_intR x -> is_intR (round m x).
Proof.
  intros x m h.
  rewrite is_intR_FIX_format.
  apply FIX_format_generic.
  apply generic_round_generic.
  apply FIX_exp_valid.
  apply fexp_Valid.
  apply valid_rnd_round_mode.
  apply generic_format_FIX.
  rewrite <-is_intR_FIX_format; assumption.
Qed.

(* Why3 goal *)
Definition is_int : t -> Prop.
Proof.
 exact (fun x => is_finite x /\ is_intR (to_real x)).
Defined.

Hint Unfold is_int.

Lemma is_int_or_not: forall (x:t), is_int x \/ ~ is_int x.
Proof.
  intro x.
  destruct x.
  - left.
    split.
    easy.
    rewrite B754_zero_to_real.
    unfold is_intR.
    rewrite Zfloor_IZR; auto.
  - right; intro h; destruct h; easy.
  - right; intro h; destruct h; easy.
  - set (x := (B754_finite s m e e0)).
    unfold is_int, is_intR.
    destruct (Req_dec (to_real x) (IZR (floor (to_real x)))).
    left.
    rewrite H, Zfloor_IZR; easy.
    right.
    intro h; destruct h; auto.
Qed.

Lemma Bmax_rep_int_is_int: is_int Bmax_rep_int.
Proof.
  split. easy.
  rewrite Bmax_rep_int_to_real.
  apply is_intR_IZR.
Qed.

Lemma B754_zero_is_int : forall {b}, (is_int (B754_zero b)).
Proof.
  split. easy.
  rewrite B754_zero_to_real.
  unfold is_intR.
  now rewrite Zfloor_IZR.
Qed.

Lemma max_value_is_int : is_int max_value.
Proof.
  split. easy.
  unfold is_intR.
  rewrite max_value_to_real, max_real_int.
  rewrite Floor_int.
  reflexivity.
Qed.

(* TODO: add to theory *)
Lemma neg_is_int : forall {x}, is_int x -> is_int (neg x).
Proof.
  intros x (h,g).
  destruct (neg_finite _ h).
  split; auto.
  rewrite H0.
  rewrite g.
  unfold is_intR.
  rewrite <- opp_IZR at 2.
  rewrite Zfloor_IZR.
  symmetry; apply opp_IZR.
Qed.

(* Why3 goal *)
Lemma zeroF_is_int : is_int zeroF.
Proof.
  apply B754_zero_is_int.
Qed.

(* Why3 goal *)
Lemma of_int_is_int :
  forall (m:ieee_float.RoundingMode.mode) (x:Numbers.BinNums.Z),
  in_int_range x -> is_int (of_int m x).
Proof.
  intros m x (h1,h2).
  assert (no_overflow m (IZR x)) as h3.
  apply Bounded_real_no_overflow.
  unfold in_range.
  rewrite max_real_int.
  rewrite <-opp_IZR.
  split; apply IZR_le; assumption.
  destruct (of_int_correct h3) as (h4,(h5,_)).
  split; auto.
  rewrite h4.
  apply is_intR_round.
  apply is_intR_IZR.
Qed.

Lemma int_to_real_ : forall {m:mode} {x:t}, (is_int x) ->
  ((to_real x) = (BuiltIn.IZR (to_int m x))).
Proof.
intros m x h1.
destruct h1.
assert (is_intR (to_real x)) by assumption.
unfold is_intR in H0.
unfold to_int.
fold (to_real x).
case m;
  [auto|
   destruct valid_rnd_NA|
   destruct valid_rnd_UP|
   destruct valid_rnd_DN|
   destruct valid_rnd_ZR]; rewrite H0;
rewrite Zrnd_IZR; try easy.
apply valid_rnd_N.
Qed.

(* TODO: add to theory? *)
Lemma neg_int_to_int : forall {x} {m:mode}, is_int x -> to_int m (neg x) = (- (to_int m x))%Z.
Proof.
  intros x m h.
  apply eq_IZR.
  rewrite FromInt.Neg, <-(int_to_real_ h), <-(int_to_real_ (neg_is_int h)).
  destruct h.
  apply neg_finite; auto.
Qed.

Lemma Bmax_rep_int_to_int: forall {m}, to_int m Bmax_rep_int = pow2sb.
Proof.
  intro m.
  apply eq_IZR.
  rewrite <-int_to_real_.
  apply Bmax_rep_int_to_real.
  apply Bmax_rep_int_is_int.
Qed.

Lemma pow2sb_finite : forall (m:mode), is_finite (of_int m pow2sb).
Proof.
  intro.
  apply of_int_correct.
  apply Bounded_real_no_overflow.
  apply rep_int_in_range.
  split; auto with zarith.
  unfold pow2sb.
  assert (0 <= 2 ^ sb)%Z by (apply Z.pow_nonneg; auto with zarith).
  auto with zarith.
Qed.

Lemma Bmax_rep_int_of_int: forall {m:mode}, Bmax_rep_int = of_int m pow2sb.
Proof.
  intro m.
  pose proof pow2sb_finite.
  apply feq_eq; try easy.
  rewrite to_real_eq; try easy.

  assert (- pow2sb <= pow2sb <= pow2sb)%Z.
  split; auto with zarith.
  assert (0 < pow2sb)%Z.
  apply (Z.pow_pos_nonneg 2 sb).
  easy.
  apply Z.lt_le_incl, Hsb'.
  auto with zarith.

  destruct (@of_int_correct m pow2sb) as (f,_); auto.
  apply Bounded_real_no_overflow.
  apply rep_int_in_range; auto.

  rewrite f, Bmax_rep_int_to_real.
  symmetry.
  apply Exact_rounding_for_integers; auto.
Qed.

(* Why3 goal *)
Lemma big_float_is_int :
  forall (m:ieee_float.RoundingMode.mode) (i:t), is_finite i ->
  le i (neg (of_int m pow2sb)) \/ le (of_int m pow2sb) i -> is_int i.
Proof.
  intros m i h1 h2.
  destruct i; try easy.
  apply B754_zero_is_int.
  split; auto.
  rewrite <-Bmax_rep_int_of_int in h2.
  unfold to_real, B2R, F2R,Fnum,Fexp.

  assert (1 <= e)%Z.
  { unfold le, Bcompare in h2; simpl SpecFloat.SFcompare in h2.
    destruct s.
    destruct h2 as [h2|h2]. 2: easy.
    destruct (Z_lt_le_dec e 1%Z); auto.
    rewrite Zcompare_Lt in h2; auto.
    easy.
    destruct h2 as [h2|h2]. easy.
    destruct e; try easy.
    pose proof (Pos2Z.is_pos p).
    auto with zarith. }

  rewrite <- IZR_Zpower by auto with zarith.
  rewrite <- mult_IZR.
  apply is_intR_IZR.
Qed.

Lemma max_value_to_int : forall m, to_int m max_value = max_int.
Proof.
  intro m.
  apply eq_IZR.
  rewrite <-max_real_int, <-int_to_real_, max_value_to_real.
  reflexivity.
  unfold is_int.

  apply max_value_is_int.
Qed.

Lemma neg_to_int_max_value : forall {m}, (- to_int m max_value)%Z = to_int m (neg max_value).
Proof.
  intro m.
  destruct (valid_rnd_round_mode m).
  pose proof max_value_is_int as H.
  pose proof (neg_is_int H).
  apply eq_IZR.
  rewrite Ropp_Ropp_IZR.
  rewrite <-int_to_real_, <-int_to_real_  by auto.
  now destruct (neg_finite max_value) as (_,h).
Qed.

Lemma is_finite_range_to_int : forall {x} m, (is_finite x) -> (in_range (IZR (to_int m x))).
Proof.
  intros x m h1.
  apply Rabs_le_inv.
  rewrite Abs.Abs_le, max_real_int, <-opp_IZR, <-(max_value_to_int m), neg_to_int_max_value.

  pose proof (bounded_floats_le _ h1).
  pose proof (abs_le_inv H) as (H1,H2).
  now split; apply IZR_le; apply to_int_le.
Qed.

Lemma is_finite_to_int: forall {x} (m1 m2:mode), is_finite x -> no_overflow m1 (IZR (to_int m2 x)).
Proof.
  intros x m1 m2 h;
  apply (Bounded_real_no_overflow m1 _ (is_finite_range_to_int m2 h)).
Qed.

Lemma is_finite_to_int2: forall {x} m, is_finite x -> (- max_int <= to_int m x <= max_int)%Z.
Proof.
  intros x m h.
  rewrite <-(@max_value_to_int m).
  rewrite (@neg_to_int_max_value m).
  pose proof (bounded_floats_le _ h).
  apply abs_le_inv in H.
  destruct H.
  now split; apply to_int_le.
Qed.

Lemma roundToIntegral_finite: forall m {x}, is_finite x -> is_finite (roundToIntegral m x).
Proof.
  intros m x h; destruct x; auto.
  unfold roundToIntegral.
  destruct Z.eq_dec; auto.
  apply of_int_correct.
  apply (is_finite_to_int RTZ m h).
Qed.

(* Why3 goal *)
Lemma roundToIntegral_is_int :
  forall (m:ieee_float.RoundingMode.mode) (x:t), is_finite x ->
  is_int (roundToIntegral m x).
Proof.
  intros m x h1.
  destruct x; try easy.
  + apply zeroF_is_int.
  + simpl.
    destruct Z.eq_dec.
    split;[apply h1|].
    simpl; unfold is_intR.
    now rewrite Zfloor_IZR.
    change (is_int (of_int RTZ (to_int m (B754_finite s m0 e e0)))).
    apply of_int_is_int.
    apply is_finite_to_int2.
    assumption.
Qed.

(* Why3 goal *)
Lemma eq_is_int : forall (x:t) (y:t), eq x y -> is_int x -> is_int y.
Proof.
  intros x y h1 (h2,h3).
  unfold is_int.
  split; [apply (eq_finite_dist h1); auto|].
  unfold is_intR in *.
  apply to_real_eq_alt in h1.
  rewrite h1 in *; assumption.
Qed.

(* Why3 goal *)
Lemma add_int :
  forall (x:t) (y:t) (m:ieee_float.RoundingMode.mode), is_int x ->
  is_int y -> is_finite (add m x y) -> is_int (add m x y).
Proof.
intros x y m (h1,h1') (h2,h2') h3.
destruct (add_finite_rev_n' m x y h3).
+ destruct H.
  unfold is_int.
  split; auto.
  rewrite H0.
  apply is_intR_round.
  apply is_intR_equiv.
  exists (floor (to_real x) + floor (to_real y))%Z.
  unfold is_intR in h1', h2'; rewrite h1', h2' at 1.
  symmetry; apply plus_IZR.
+ split; auto.
  rewrite max_real_int in H.
  destruct H; apply is_intR_equiv.
  exists max_int; assumption.
  exists (- max_int)%Z.
  now rewrite opp_IZR.
Qed.

(* Why3 goal *)
Lemma sub_int :
  forall (x:t) (y:t) (m:ieee_float.RoundingMode.mode), is_int x ->
  is_int y -> is_finite (sub m x y) -> is_int (sub m x y).
Proof.
intros x y m (h1,h1') (h2,h2') h3.
destruct (sub_finite_rev_n' m x y h3).
+ destruct H.
  unfold is_int.
  split; auto.
  rewrite H0.
  apply is_intR_round.
  apply is_intR_equiv.
  exists (floor (to_real x) - floor (to_real y))%Z.
  unfold is_intR in h1', h2'; rewrite h1', h2' at 1.
  symmetry; apply minus_IZR.
+ split; auto.
  rewrite max_real_int in H.
  destruct H; apply is_intR_equiv.
  exists max_int; assumption.
  exists (- max_int)%Z.
  now rewrite opp_IZR.
Qed.

(* Why3 goal *)
Lemma mul_int :
  forall (x:t) (y:t) (m:ieee_float.RoundingMode.mode), is_int x ->
  is_int y -> is_finite (mul m x y) -> is_int (mul m x y).
Proof.
intros x y m (h1,h1') (h2,h2') h3.
destruct (mul_finite_rev_n' m x y h3).
+ destruct H.
  unfold is_int.
  split; auto.
  rewrite H0.
  apply is_intR_round.
  apply is_intR_equiv.
  exists (floor (to_real x) * floor (to_real y))%Z.
  unfold is_intR in h1', h2'; rewrite h1', h2' at 1.
  symmetry; apply mult_IZR.
+ split; auto.
  rewrite max_real_int in H.
  destruct H; apply is_intR_equiv.
  exists max_int; assumption.
  exists (- max_int)%Z.
  now rewrite opp_IZR.
Qed.

(* Why3 goal *)
Lemma fma_int :
  forall (x:t) (y:t) (z:t) (m:ieee_float.RoundingMode.mode), is_int x ->
  is_int y -> is_int z -> is_finite (fma m x y z) -> is_int (fma m x y z).
Proof.
intros x y z m (h1,h1') (h2,h2') (h3,h3') h4.
destruct (fma_finite_rev_n' m x y z h4).
+ destruct H.
  unfold is_int.
  split; auto.
  rewrite H0.
  apply is_intR_round.
  apply is_intR_equiv.
  exists (floor (to_real x) * floor (to_real y) + floor (to_real z))%Z.
  unfold is_intR in h1', h2', h3'; rewrite h1', h2', h3' at 1.
  rewrite plus_IZR, mult_IZR; reflexivity.
+ split; auto.
  rewrite max_real_int in H.
  destruct H; apply is_intR_equiv.
  exists max_int; assumption.
  exists (- max_int)%Z.
  rewrite opp_IZR; assumption.
Qed.

(* Why3 goal *)
Lemma neg_int : forall (x:t), is_int x -> is_int (neg x).
Proof.
intros x (h1,h2).
destruct (neg_finite x h1).
split; try easy.
unfold is_intR in *.
rewrite H0.
rewrite h2 at 2.
rewrite <- opp_IZR, Zfloor_IZR, opp_IZR.
apply f_equal, h2.
Qed.

(* Why3 goal *)
Lemma abs_int : forall (x:t), is_int x -> is_int (abs x).
Proof.
intros x (h1,h2).
destruct (abs_finite x h1) as (h3,(h4,h5)).
split; try easy.
unfold is_intR in *.
rewrite h4.
rewrite h2 at 2.
rewrite <- abs_IZR, Zfloor_IZR, abs_IZR.
apply f_equal, h2.
Qed.

(* Why3 goal *)
Lemma is_int_of_int :
  forall (x:t) (m:ieee_float.RoundingMode.mode)
    (m':ieee_float.RoundingMode.mode),
  is_int x -> eq x (of_int m' (to_int m x)).
Proof.
  intros x m m' h1.
  assert (h1':=h1).
  destruct h1 as (h1,h2).
  assert (no_overflow m' (IZR (to_int m x))) by
      (apply is_finite_to_int; auto).
  destruct (of_int_correct H) as (h3,(h4,h5)); auto.
  rewrite to_real_eq; auto.
  rewrite h3, <-int_to_real_; auto.
  symmetry; apply Round_to_real; auto.
Qed.

(* Why3 goal *)
Lemma is_int_to_int :
  forall (m:ieee_float.RoundingMode.mode) (x:t), is_int x ->
  in_int_range (to_int m x).
Proof.
intros m x h1.
pose proof (@int_to_real_ m x h1).
unfold in_int_range.
destruct h1.
apply is_finite1 in H0.
unfold in_range in H0.
destruct H0.
split; apply le_IZR; try rewrite FromInt.Neg; rewrite <-max_real_int, <-H; auto.
Qed.

(* Why3 goal *)
Lemma is_int_is_finite : forall (x:t), is_int x -> is_finite x.
Proof.
intros x (h,_); assumption.
Qed.

(* Why3 goal *)
Lemma int_to_real :
  forall (m:ieee_float.RoundingMode.mode) (x:t), is_int x ->
  ((to_real x) = (BuiltIn.IZR (to_int m x))).
Proof.
intros m x.
apply int_to_real_.
Qed.

Lemma of_int_to_real : forall (m:mode) (x:Z), (no_overflow m
  (BuiltIn.IZR x)) -> ((to_real (of_int m x)) = (round m
  (BuiltIn.IZR x))).
Proof.
  intros m x h1.
  apply (of_int_correct h1).
Qed.

(* TODO: add to theory ? *)
Lemma to_real_roundToIntegral: forall {x} m, is_finite x -> to_real (roundToIntegral m x) = IZR (to_int m x).
Proof.
  intros x m h.
  unfold roundToIntegral.
  destruct Z.eq_dec.

  destruct x; try easy.
  rewrite B754_zero_to_real, e; auto.
  rewrite B754_zero_to_real, e; auto.

  destruct x; try easy.
  contradict n.
  apply to_int_B754_zero.

  set (x:= B754_finite s m0 e e0); fold x in h, h.
  change (to_real (of_int RTZ (to_int m x)) = IZR (to_int m x)).

  assert (is_finite Bmax_rep_int) by auto.
  destruct (neg_finite _ H) as (H0,_).

  assert (((le (neg Bmax_rep_int) x) /\ (le x Bmax_rep_int))
       \/ ((le x (neg Bmax_rep_int)) \/ (le Bmax_rep_int x))) as h1.
  destruct (le_or_lt_or_nan x Bmax_rep_int) as [h1|[h1|[h1|h1]]].
  + destruct (le_or_lt_or_nan (neg Bmax_rep_int) x) as [h2|[h2|[h2|h2]]].
    - left; split; easy.
    - right; left; apply lt_le; auto.
    - destruct (neg Bmax_rep_int); easy.
    - destruct x; easy.
  + right; right; apply lt_le; auto.
  + destruct x; easy.
  + destruct Bmax_rep_int; easy.

  + destruct h1.
    - destruct H1.
      apply (@to_int_le _ _ m H0 h) in H1.
      apply (@to_int_le _ _ m h H) in H2.
      rewrite (neg_int_to_int Bmax_rep_int_is_int) in H1.
      rewrite Bmax_rep_int_to_int in H1, H2.
      rewrite of_int_to_real.
      rewrite Exact_rounding_for_integers; auto.
      unfold in_safe_int_range; auto.
      apply Bounded_real_no_overflow.
      apply rep_int_in_range; auto.
    - rewrite (@Bmax_rep_int_of_int m) in H1.
      pose proof (big_float_is_int m _ h H1).
      rewrite of_int_to_real.
      rewrite <-int_to_real; auto.
      rewrite Round_to_real; auto.
      apply Bounded_real_no_overflow.
      apply is_finite_range_to_int; auto.
Qed.

(* Why3 goal *)
Lemma truncate_int :
  forall (m:ieee_float.RoundingMode.mode) (i:t), is_int i ->
  eq (roundToIntegral m i) i.
Proof.
  intros m i (h1,h2).
  pose proof (roundToIntegral_finite m h1).
  rewrite eq_to_real_finite; auto.
  rewrite to_real_roundToIntegral; auto.
  symmetry.
  apply int_to_real; auto.
Qed.

(* Why3 goal *)
Lemma truncate_neg :
  forall (x:t), is_finite x -> is_negative x ->
  ((roundToIntegral ieee_float.RoundingMode.RTZ x) =
   (roundToIntegral ieee_float.RoundingMode.RTP x)).
Proof.
  intros x h1 h2.
  destruct x; try easy.
  simpl roundToIntegral.
  pose proof (negative_to_real _ h1 h2).
  pose proof (Ztrunc_ceil _ H).
  simpl in H0.
  rewrite H0.
  reflexivity.
Qed.

(* Why3 goal *)
Lemma truncate_pos :
  forall (x:t), is_finite x -> is_positive x ->
  ((roundToIntegral ieee_float.RoundingMode.RTZ x) =
   (roundToIntegral ieee_float.RoundingMode.RTN x)).
Proof.
  intros x h1 h2.
  destruct x; try easy.
  simpl roundToIntegral.
  pose proof (positive_to_real _ h1 h2).
  pose proof (Ztrunc_floor _ H).
  simpl in H0.
  rewrite H0.
  reflexivity.
Qed.

(* Why3 goal *)
Lemma ceil_le :
  forall (x:t), is_finite x ->
  le x (roundToIntegral ieee_float.RoundingMode.RTP x).
Proof.
intros x h1.
pose proof (roundToIntegral_finite RTP h1).
rewrite le_to_real; auto.
rewrite to_real_roundToIntegral; auto.
simpl.
apply Zceil_ub.
Qed.

(* Why3 goal *)
Lemma ceil_lest :
  forall (x:t) (y:t), le x y /\ is_int y ->
  le (roundToIntegral ieee_float.RoundingMode.RTP x) y.
Proof.
intros x y (h1,h2).
destruct (le_special _ _ h1) as [h|[h|h]]; try easy.
- destruct h.
  pose proof (roundToIntegral_finite RTP H).
  rewrite le_to_real; auto.
  rewrite to_real_roundToIntegral; auto.
  simpl.
  rewrite (int_to_real RTP _ h2).
  apply IZR_le, Zceil_glb.
  rewrite <- (int_to_real RTP _ h2).
  apply le_to_real; auto.
- destruct h as (h,_).
  unfold is_minus_infinity in h.
  destruct x; easy.
- unfold is_plus_infinity in h.
  destruct h, h2, y; try easy.
Qed.

(* Why3 goal *)
Lemma ceil_to_real :
  forall (x:t), is_finite x ->
  ((to_real (roundToIntegral ieee_float.RoundingMode.RTP x)) =
   (BuiltIn.IZR (real.Truncate.ceil (to_real x)))).
Proof.
  intros x h.
  rewrite to_real_roundToIntegral; auto.
Qed.

(* Why3 goal *)
Lemma ceil_to_int :
  forall (m:ieee_float.RoundingMode.mode) (x:t), is_finite x ->
  ((to_int m (roundToIntegral ieee_float.RoundingMode.RTP x)) =
   (real.Truncate.ceil (to_real x))).
Proof.
  intros m x h.
  unfold to_int.
  rewrite to_real_roundToIntegral; auto.
  destruct (valid_rnd_round_mode m) as (_,h').
  destruct m; apply (h' (to_int RTP x)).
Qed.

(* Why3 goal *)
Lemma floor_le :
  forall (x:t), is_finite x ->
  le (roundToIntegral ieee_float.RoundingMode.RTN x) x.
Proof.
  intros x h1.
  pose proof (roundToIntegral_finite RTN h1).
  rewrite le_to_real; auto.
  rewrite to_real_roundToIntegral; auto.
  simpl.
  apply Zfloor_lb.
Qed.

(* Why3 goal *)
Lemma floor_lest :
  forall (x:t) (y:t), le y x /\ is_int y ->
  le y (roundToIntegral ieee_float.RoundingMode.RTN x).
Proof.
  intros x y (h1,h2).
  destruct (le_special _ _ h1) as [h|[h|h]]; try easy.
  - destruct h.
    pose proof (roundToIntegral_finite RTN H0).
    rewrite le_to_real; auto.
    rewrite to_real_roundToIntegral; auto.
    simpl.
    rewrite (int_to_real RTN _ h2).
    apply IZR_le, Zfloor_lub.
    rewrite <- (int_to_real RTN _ h2).
    apply le_to_real; auto.
  - destruct h2 as (h2,_).
    unfold is_minus_infinity in h.
    destruct y; easy.
  - unfold is_plus_infinity in h.
    destruct h; destruct H; destruct H0, h2, x; try easy.
Qed.

(* Why3 goal *)
Lemma floor_to_real :
  forall (x:t), is_finite x ->
  ((to_real (roundToIntegral ieee_float.RoundingMode.RTN x)) =
   (BuiltIn.IZR (real.Truncate.floor (to_real x)))).
Proof.
  intros x h.
  rewrite to_real_roundToIntegral; auto.
Qed.

(* Why3 goal *)
Lemma floor_to_int :
  forall (m:ieee_float.RoundingMode.mode) (x:t), is_finite x ->
  ((to_int m (roundToIntegral ieee_float.RoundingMode.RTN x)) =
   (real.Truncate.floor (to_real x))).
Proof.
  intros m x h.
  unfold to_int.
  rewrite to_real_roundToIntegral; auto.
  destruct (valid_rnd_round_mode m) as (_,h').
  destruct m; apply (h' (to_int RTN x)).
Qed.

Lemma same_sign_roundToIntegral:
  forall {x} (m:mode), ~ is_nan x -> same_sign (roundToIntegral m x) x.
Proof.
  intros x m h.
  unfold same_sign.
  destruct x; try (now elim h); try (destruct s; simpl; now auto); clear h.
  set (x:=B754_finite s m0 e e0).
  assert (no_overflow RTZ (IZR (to_int m x))) by
      now apply is_finite_to_int.
  destruct (of_int_correct H) as (_,(_,h1)); clear H.
  assert (is_finite x) as h2 by easy.
  pose proof (roundToIntegral_finite m h2).
  destruct s; simpl;[right|left];split;auto.
  + apply is_negative_Bsign; auto.
    change (~ is_nan (roundToIntegral m x)); destruct (roundToIntegral m x); easy.
    assert (to_int m x <= 0)%Z.
    apply is_negative_to_int; easy.
    destruct (Z_le_lt_eq_dec _ _ H0).
    - rewrite Zcompare_Lt in h1 by auto.
      destruct Z.eq_dec; auto.
    - destruct Z.eq_dec; auto.
  + apply is_positive_Bsign; auto.
    change (~ is_nan (roundToIntegral m x)); destruct (roundToIntegral m x); easy.
    assert (0 <= to_int m x)%Z.
    apply is_positive_to_int; easy.
    destruct (Z_le_lt_eq_dec _ _ H0).
    - rewrite Zcompare_Gt in h1 by auto.
      destruct Z.eq_dec; auto.
    - symmetry in e1.
      destruct Z.eq_dec; easy.
Qed.

Lemma same_sign_roundToIntegral2:
  forall {x} {m m':mode}, ~ is_nan x -> same_sign (roundToIntegral m x) (roundToIntegral m' x).
Proof.
  intros x m m' h.
  pose proof (same_sign_roundToIntegral m h).
  pose proof (same_sign_roundToIntegral m' h).
  unfold same_sign in *.
  pose proof (negative_xor_positive x).
  destruct H as [(H,H')|(H,H')], H0 as [(H0,H0')|(H0,H0')]; auto.
  contradict H1; auto.
  contradict H1; auto.
Qed.

Lemma no_overflow_to_real_min_RTN:
  forall x, is_finite x -> no_overflow RNE (to_real x - to_real (roundToIntegral RTN x)).
Proof.
  intros x h.
  rewrite to_real_roundToIntegral; auto.
  unfold to_int.
  apply Bounded_real_no_overflow.
  pose proof (Zfloor_ub (to_real x)).
  pose proof (Zfloor_lb (to_real x)).
  unfold in_range.
  pose proof max_real_ge_6.
  fold (to_real x).
  split; lra.
Qed.

Lemma ceil_lb: forall x, ((IZR (ceil x) - 1) < x).
Proof.
  intro.
  case (Req_dec (IZR (Zfloor x)) x); intro.
  rewrite <-H, Zceil_IZR, H; simpl; lra.
  rewrite (Zceil_floor_neq _ H).
  rewrite plus_IZR; simpl.
  pose proof (Zfloor_lb x).
  destruct (Rle_lt_or_eq_dec _ _ H0); try easy.
  lra.
Qed.

Lemma no_overflow_to_real_RTP_min:
  forall x, is_finite x -> no_overflow RNE (to_real (roundToIntegral RTP x) - to_real x).
Proof.
  intros x h.
  rewrite to_real_roundToIntegral; auto.
  unfold to_int.
  apply Bounded_real_no_overflow.
  pose proof (Zceil_ub (to_real x)).
  pose proof (ceil_lb (to_real x)).
  unfold in_range.
  pose proof max_real_ge_6.
  fold (to_real x).
  split; lra.
Qed.

(* Why3 goal *)
Lemma RNA_down :
  forall (x:t),
  lt
  (sub ieee_float.RoundingMode.RNE x
   (roundToIntegral ieee_float.RoundingMode.RTN x))
  (sub ieee_float.RoundingMode.RNE
   (roundToIntegral ieee_float.RoundingMode.RTP x) x) ->
  ((roundToIntegral ieee_float.RoundingMode.RNA x) =
   (roundToIntegral ieee_float.RoundingMode.RTN x)).
Proof.
  intros x h.
  destruct x; try easy.
  set (x:=(B754_finite s m e e0)); fold x in h.
  assert (forall m', is_finite (roundToIntegral m' x)) as h1.
  intro m'.
  apply roundToIntegral_finite; try easy.
  apply to_real_refl; try easy.
  2: apply same_sign_roundToIntegral2; easy.

  rewrite to_real_roundToIntegral, to_real_roundToIntegral; try easy.
  f_equal.
  unfold to_int.
  apply Znearest_imp.
  rewrite Rabs_pos_eq.
  2: pose proof (Zfloor_lb (to_real x)); fold (to_real x); lra.

  assert (is_finite x) as x_fin by easy.
  pose proof (no_overflow_to_real_min_RTN _ x_fin) as h2.
  pose proof (no_overflow_to_real_RTP_min _ x_fin) as h3.

  assert (is_finite (roundToIntegral RTN x)) as rtn_fin by auto.
  assert (is_finite (roundToIntegral RTP x)) as rtp_fin by auto.
  destruct (sub_finite _ _ _ x_fin rtn_fin h2) as (h4,h4').
  destruct (sub_finite _ _ _ rtp_fin x_fin h3) as (h5,h5').
  clear x_fin h2 h3 rtn_fin rtp_fin.

  rewrite lt_finite in h; auto.
  rewrite h4' in h; auto.
  rewrite h5' in h; auto.

  fold (to_real x).
  case (Req_dec (IZR (Zfloor (to_real x))) (to_real x)); intro.
  lra.

  apply round_lt in h.
  rewrite to_real_roundToIntegral, to_real_roundToIntegral in h; try easy.
  unfold to_int in h.
  rewrite Zceil_floor_neq, plus_IZR in h; auto.
  fold (to_real x) in h.
  lra.
Qed.

(* Why3 goal *)
Lemma RNA_up :
  forall (x:t),
  lt
  (sub ieee_float.RoundingMode.RNE
   (roundToIntegral ieee_float.RoundingMode.RTP x) x)
  (sub ieee_float.RoundingMode.RNE x
   (roundToIntegral ieee_float.RoundingMode.RTN x)) ->
  ((roundToIntegral ieee_float.RoundingMode.RNA x) =
   (roundToIntegral ieee_float.RoundingMode.RTP x)).
Proof.
  intros x h.
  destruct x; try easy.
  set (x:=(B754_finite s m e e0)); fold x in h.
  assert (forall m', is_finite (roundToIntegral m' x)) as h1.
  intro m'.
  apply roundToIntegral_finite; try easy.
  apply to_real_refl; try easy.
  2: apply same_sign_roundToIntegral2; easy.

  rewrite to_real_roundToIntegral, to_real_roundToIntegral; try easy.
  f_equal.
  unfold to_int.
  apply Znearest_imp.
  rewrite Rabs_left1.
  2: pose proof (Zceil_ub (to_real x)); fold (to_real x); lra.
  rewrite Ropp_minus_distr.

  assert (is_finite x) as x_fin by easy.
  pose proof (no_overflow_to_real_min_RTN _ x_fin) as h2.
  pose proof (no_overflow_to_real_RTP_min _ x_fin) as h3.

  assert (is_finite (roundToIntegral RTN x)) as rtn_fin by auto.
  assert (is_finite (roundToIntegral RTP x)) as rtp_fin by auto.
  destruct (sub_finite _ _ _ x_fin rtn_fin h2) as (h4,h4').
  destruct (sub_finite _ _ _ rtp_fin x_fin h3) as (h5,h5').
  clear x_fin h2 h3 rtn_fin rtp_fin.

  rewrite lt_finite in h; auto.
  rewrite h4' in h; auto.
  rewrite h5' in h; auto.

  fold (to_real x).
  case (Req_dec (IZR (Zceil (to_real x))) (to_real x)); intro.
  lra.

  apply round_lt in h.
  rewrite to_real_roundToIntegral, to_real_roundToIntegral in h; try easy.
  unfold to_int in h.
  assert (IZR (floor (to_real x)) <> to_real x).
  intro.
  rewrite <-H0 in H.
  rewrite Zceil_IZR in H.
  auto.

  rewrite Zceil_floor_neq, plus_IZR in h; auto.
  rewrite Zceil_floor_neq, plus_IZR; auto.
  fold (to_real x) in h; lra.
Qed.

Lemma sterbenz_round: forall x y m,
    to_real y / 2 <= to_real x <= 2 * to_real y ->
    round m (to_real x - to_real y) = to_real x - to_real y.
Proof.
  intros x y m h.
  assert (generic_format radix2 fexp (to_real x - to_real y)).
  { apply Sterbenz.sterbenz.
    apply fexp_Valid.
    apply fexp_monotone.
    apply generic_format_B2R.
    apply generic_format_B2R.
    exact h. }
  apply round_generic; auto.
  apply valid_rnd_round_mode.
Qed.

Lemma sterbenz_round_opp: forall x y m,
    to_real y / 2 <= to_real x <= 2 * to_real y ->
    round m (to_real y - to_real x) = to_real y - to_real x.
Proof.
  intros x y m h.
  assert (generic_format radix2 fexp (to_real y - to_real x)).
  { replace (to_real y - to_real x) with (- (to_real x - to_real y)) by ring.
    apply generic_format_opp.
    apply Sterbenz.sterbenz.
    apply fexp_Valid.
    apply fexp_monotone.
    apply generic_format_B2R.
    apply generic_format_B2R.
    exact h. }
  apply round_generic; auto.
  apply valid_rnd_round_mode.
Qed.

Lemma sterbenz_round_2: forall x y m, is_finite y -> is_finite x ->
    2 * to_real y <= to_real x <= to_real y / 2 ->
    round m (to_real x - to_real y) = to_real x - to_real y.
Proof.
  intros x y m h h' h2.
  replace (to_real x - to_real y) with (-to_real y - (- to_real x)) by field.
  destruct (neg_finite _ h) as (_,h1); rewrite <-h1;
  destruct (neg_finite _ h') as (_,h1'); rewrite <-h1'.
  apply sterbenz_round_opp.
  rewrite h1, h1'.
  destruct h2.
  assert (forall x, -x = -1*x) as h2 by (intro; ring).
  split.
  - rewrite h2, (h2 (to_real x)).
    rewrite Real.assoc_mul_div by (apply Rgt_not_eq; lra).
    apply Rmult_le_compat_neg_l; lra.
  - rewrite h2, (h2 (to_real y)).
    replace (2 * (-1 * to_real y)) with (-1 * (2 * to_real y)) by field.
    apply Rmult_le_compat_neg_l; lra.
Qed.

Lemma RTN_not_far: forall x,
    is_finite x -> 1 <= to_real x ->
    to_real (roundToIntegral RTN x) / 2 <= to_real x <= 2 * to_real (roundToIntegral RTN x).
Proof.
  intros x h h1.
  rewrite floor_to_real; auto.
  pose proof (Zfloor_lb (to_real x));
  pose proof (Zfloor_ub (to_real x)).
  split. lra.
  apply Rlt_le.
  apply Rlt_le_trans with (r2 := IZR (floor (to_real x)) + 1); auto.
  assert (1 <= IZR (floor (to_real x))).
  { pose proof (Rle_lt_trans _ _ _ h1 H0).
    rewrite <- plus_IZR in H1.
    apply lt_IZR in H1.
    apply IZR_le.
    auto with zarith. }
  lra.
Qed.

Lemma RTN_not_far_opp: forall x,
    is_finite x -> to_real x <= -/2 ->
    2 * to_real (roundToIntegral RTN x) <= to_real x <= to_real (roundToIntegral RTN x) / 2.
Proof.
  intros x h h1.
  rewrite floor_to_real; auto.
  pose proof (Zfloor_lb (to_real x));
  pose proof (Zfloor_ub (to_real x)).
  split. lra.
  destruct (Rle_lt_dec (to_real x) (-1)). lra.
  assert (IZR (floor (to_real x)) = -1).
  { assert (IZR (floor(to_real x)) < 0) by lra.
    assert (-2 < IZR (floor (to_real x))) by lra.
    apply lt_IZR in H1; apply lt_IZR in H2.
    now replace (floor (to_real x)) with (-1)%Z by lia. }
  lra.
Qed.

Lemma RTP_not_far: forall x,
    is_finite x -> /2 <= to_real x ->
    to_real x / 2 <= to_real (roundToIntegral RTP x) <= 2 * to_real x.
Proof.
  intros x h h1.
  rewrite ceil_to_real; auto.
  pose proof (ceil_lb (to_real x));
  pose proof (Zceil_ub (to_real x)).
  split. lra.
  destruct (Rle_lt_dec 1 (to_real x) ); try lra.
  assert (IZR (ceil (to_real x)) = 1).
  { assert (0 < IZR (ceil( to_real x))) by lra.
    assert (IZR (ceil(to_real x)) < 2) by lra.
    apply lt_IZR in H1; apply lt_IZR in H2.
    now replace (ceil (to_real x)) with 1%Z by lia. }
  lra.
Qed.

Lemma RTP_not_far_opp: forall x,
    is_finite x -> to_real x <= -1 ->
    2 * to_real x <= to_real (roundToIntegral RTP x) <= to_real x / 2.
Proof.
  intros x h h1.
  rewrite ceil_to_real; auto.
  pose proof (ceil_lb (to_real x));
  pose proof (Zceil_ub (to_real x)).
  split. lra.
  apply Rmult_le_reg_r with (r:=2); try lra.
  replace (to_real x / 2 * 2) with (to_real x) by field.
  apply Rlt_le.
  apply Rle_lt_trans with (r2 := IZR (ceil (to_real x)) - 1); auto.
  assert (IZR (ceil (to_real x)) <= -1).
  { pose proof (Rlt_le_trans _ _ _ H h1).
    rewrite <- (minus_IZR _ 1) in H1.
    apply (lt_IZR _ (-1)) in H1.
    apply (IZR_le _ (-1)).
    auto with zarith. }
  lra.
Qed.

Lemma round_plus_weak: forall x y m,
    Rabs (to_real x + to_real y) <= Rmin (Rabs (to_real x)) (Rabs (to_real y)) ->
    round m (to_real x + to_real y) = to_real x + to_real y.
Proof.
  intros x y m h.
  assert (generic_format radix2 fexp (to_real x + to_real y)).
  { apply Sterbenz.generic_format_plus_weak.
    apply fexp_Valid.
    apply fexp_monotone.
    apply generic_format_B2R.
    apply generic_format_B2R.
    exact h. }
  apply round_generic; auto.
  apply valid_rnd_round_mode.
Qed.

Lemma half_bounded: SpecFloat.bounded sb emax (shift_pos (sb_pos - 1) 1) (- sb) = true.
Proof.
  unfold SpecFloat.bounded.
  apply Bool.andb_true_iff; split.
  unfold SpecFloat.canonical_mantissa.
  apply Zeq_bool_true.
  rewrite Digits.Zpos_digits2_pos, shift_pos_correct.
  rewrite Zmult_1_r, Z.pow_pos_fold.
  rewrite Digits.Zdigits_Zpower by easy.
  rewrite Pos2Z.inj_sub by exact sb_gt_1.
  fold sb.
  unfold SpecFloat.fexp, FLT_exp, SpecFloat.emin.
  replace (sb - 1 + 1 + - sb)%Z with 0%Z by ring.
  apply Z.max_l.
  pose sb_gt_1; pose Hemax'; lia.
  apply Zle_bool_true.
  pose Hemax'; pose sb_gt_1; lia.
Qed.

Definition half: t.
Proof.
  exact (B754_finite false _ _ half_bounded).
Defined.

Lemma half_to_real : ((to_real half) = (05 / 10)%R).
Proof.
  unfold B2R, half; simpl.
  rewrite shift_pos_correct.
  rewrite Z.pow_pos_fold.
  unfold F2R.
  unfold Fnum, Fexp.
  rewrite Zmult_1_r.
  change 2%Z with (radix_val radix2).
  rewrite IZR_Zpower by easy.
  rewrite <-bpow_plus.
  rewrite Pos2Z.inj_sub by exact sb_gt_1.
  rewrite <-Pos2Z.opp_pos.
  replace (Z.pos sb_pos - 1 + - Z.pos sb_pos)%Z with (- 1)%Z by ring.
  unfold bpow.
  change (Z.pow_pos radix2 1)%Z with 2%Z.
  field.
Qed.

Lemma eq_diff_floor_ceil: forall {x}, eq (sub RNE x (roundToIntegral RTN x)) (sub RNE (roundToIntegral RTP x) x) -> to_real x - IZR (floor (to_real x)) = IZR (ceil (to_real x)) - to_real x.
Proof.
  intros x h.
  destruct x; try easy.
  - rewrite B754_zero_to_real.
    rewrite Zfloor_IZR, Zceil_IZR; auto.
  - simpl.
    rewrite Zfloor_IZR, Zceil_IZR; auto.
  - set (x:=(B754_finite s m e e0)); fold x in h.
    assert (forall m', is_finite (roundToIntegral m' x)) as h1 by
          (intro m'; apply roundToIntegral_finite; easy).

    assert (is_finite x) as x_fin by easy.
    pose proof (no_overflow_to_real_min_RTN _ x_fin) as h2.
    pose proof (no_overflow_to_real_RTP_min _ x_fin) as h3.

    assert (is_finite (roundToIntegral RTN x)) as rtn_fin by auto.
    assert (is_finite (roundToIntegral RTP x)) as rtp_fin by auto.
    destruct (sub_finite _ _ _ x_fin rtn_fin h2) as (h4,h4').
    destruct (sub_finite _ _ _ rtp_fin x_fin h3) as (h5,h5').
    clear h2 h3 rtn_fin rtp_fin.

    assert (h':=h).
    rewrite to_real_eq in h; auto.
    rewrite h4' in h; auto.
    rewrite h5' in h; auto.
    clear h4' h5'.

    destruct (Rle_lt_dec 1 (to_real x));[|destruct (Rle_lt_dec (to_real x) (-1))].

    + destruct (RTN_not_far x); auto.
      destruct (RTP_not_far x); auto; try lra.
      rewrite sterbenz_round, sterbenz_round in h by auto.
      rewrite to_real_roundToIntegral, to_real_roundToIntegral in h; auto.

    + destruct (RTN_not_far_opp x); auto; try lra.
      destruct (RTP_not_far_opp x); auto.
      rewrite sterbenz_round_2, sterbenz_round_2 in h by auto.
      rewrite to_real_roundToIntegral, to_real_roundToIntegral in h; auto.

    + destruct (Rle_lt_dec (to_real x) 0).
      destruct r1.
      * assert (floor (to_real x) = (-1)%Z).
            (apply Zfloor_imp; simpl IZR; split; lra).
        assert (ceil (to_real x) = 0%Z) by
            (apply Zceil_imp; simpl IZR; split; lra).

        revert h.
        rewrite (to_real_roundToIntegral RTP) by easy.
        unfold to_int.
        fold (to_real x).
        rewrite H1.
        rewrite Rminus_0_l.
        rewrite <-(proj2 (neg_finite _ x_fin)).
        rewrite (Round_to_real RNE) by easy.
        rewrite (proj2 (neg_finite _ x_fin)).

        { destruct (Rle_lt_dec (to_real x) (-/2)).
        - assert (
               round RNE (to_real x - to_real (roundToIntegral RTN x)) =
               to_real x - to_real (roundToIntegral RTN x)) as aux1.
           { rewrite Real.infix_mn'def, <-(proj2 (neg_finite _ (h1 RTN))).
             apply round_plus_weak.
             rewrite (proj2 (neg_finite _ (h1 RTN))).
             rewrite to_real_roundToIntegral; auto.
             unfold to_int.
             fold (to_real x).
             rewrite H0.
             rewrite <- opp_IZR; simpl IZR.
             rewrite Rabs_pos_eq, Rabs_left, Rabs_pos_eq, Rmin_left ; lra. }
           rewrite aux1.
           now rewrite to_real_roundToIntegral.

        - clear r r0.
           rewrite to_real_roundToIntegral by easy.
           unfold to_int.
           fold (to_real x).
           rewrite H0.
           replace (to_real x - -1) with (to_real x+1) by ring.
           pose proof (Rplus_lt_compat_r 1 _ _ r1).
           apply Rlt_le in H2.
           replace (-/2+1) with (5/10) in H2 by field.
           rewrite <-half_to_real in H2.
           apply (Round_monotonic RNE) in H2.
           rewrite Round_to_real in H2 by easy.
           rewrite half_to_real in H2.
           intros.
           lra. }
      * assert (floor (to_real x) = 0%Z) by
            (apply Zfloor_imp; simpl IZR; split; lra).
        assert (ceil (to_real x) = 0%Z) by
            (apply Zceil_imp; simpl IZR; split; lra).
        rewrite H0, H1, H; auto.

      * assert (floor (to_real x) = 0%Z) by
            (apply Zfloor_imp; simpl IZR; split; lra).
        assert (ceil (to_real x) = 1%Z) by
            (apply Zceil_imp; simpl IZR; split; lra).

        revert h.
        rewrite (to_real_roundToIntegral RTN) by easy.
        unfold to_int.
        fold (to_real x).
        rewrite H.
        replace (to_real x - 0) with (to_real x) by (simpl IZR ; ring).
        rewrite (Round_to_real RNE) by easy.

        { destruct (Rle_lt_dec (/2) (to_real x)).
        - assert (
               round RNE (to_real (roundToIntegral RTP x) - to_real x) =
               to_real (roundToIntegral RTP x) - to_real x) as aux1.
           { rewrite Real.infix_mn'def, <-(proj2 (neg_finite _ x_fin)).
             apply round_plus_weak.
             rewrite (proj2 (neg_finite _ x_fin)).
             rewrite to_real_roundToIntegral by easy.
             unfold to_int.
             fold (to_real x).
             rewrite H0.
             rewrite Rabs_pos_eq, Rabs_pos_eq, Rabs_left, Rmin_right; lra. }
           rewrite aux1.
           now rewrite to_real_roundToIntegral.

        - clear r r0.
           rewrite to_real_roundToIntegral by easy.
           unfold to_int.
           fold (to_real x).
           rewrite H0.
           pose proof (Ropp_lt_contravar _ _ r2).
           pose proof (Rplus_lt_compat_l 1 _ _ H1).
           apply Rlt_le in H2.
           replace (1+-/2) with (5/10) in H2 by field.
           rewrite <-half_to_real in H2.
           rewrite <-Real.infix_mn'def in H2.
           apply (Round_monotonic RNE) in H2.
           rewrite Round_to_real in H2 by easy.
           rewrite half_to_real in H2.
           intros.
           lra. }
Qed.

(* Why3 goal *)
Lemma RNA_down_tie :
  forall (x:t),
  eq
  (sub ieee_float.RoundingMode.RNE x
   (roundToIntegral ieee_float.RoundingMode.RTN x))
  (sub ieee_float.RoundingMode.RNE
   (roundToIntegral ieee_float.RoundingMode.RTP x) x) ->
  is_negative x ->
  ((roundToIntegral ieee_float.RoundingMode.RNA x) =
   (roundToIntegral ieee_float.RoundingMode.RTN x)).
Proof.
  intros x h h'.
  destruct x; try easy.
  set (x:=(B754_finite s m e e0)); fold x in h, h'.
  assert (forall m', is_finite (roundToIntegral m' x)) as h1 by
        (intro m'; apply roundToIntegral_finite; easy).
  apply to_real_refl; auto.
  2: apply same_sign_roundToIntegral2; easy.
  apply eq_diff_floor_ceil in h.

  rewrite to_real_roundToIntegral, to_real_roundToIntegral; try easy.
  f_equal.
  unfold to_int.
  fold (to_real x).

  destruct (is_int_or_not x).
  rewrite (int_to_real RTZ _ H).
  destruct (valid_rnd_round_mode RNA) as (_,H').
  simpl in H'.
  rewrite H', Zfloor_IZR; reflexivity.

  unfold Znearest.
  rewrite Rcompare_Eq.
  rewrite Zle_bool_false; auto.
  apply lt_IZR.
  apply Rle_lt_trans with (r2:=to_real x).
  apply Zfloor_lb.
  rewrite <-zeroF_to_real.
  apply lt_finite; try easy.
  rewrite is_negative_correct in h'.
  destruct h'; easy.

  rewrite Zceil_floor_neq in h.
  rewrite plus_IZR in h.
  lra.

  unfold is_int in H.
  apply Decidable.not_and in H.
  destruct H.
  now elim H.
  now apply not_eq_sym.
  now left.
Qed.

(* Why3 goal *)
Lemma RNA_up_tie :
  forall (x:t),
  eq
  (sub ieee_float.RoundingMode.RNE
   (roundToIntegral ieee_float.RoundingMode.RTP x) x)
  (sub ieee_float.RoundingMode.RNE x
   (roundToIntegral ieee_float.RoundingMode.RTN x)) ->
  is_positive x ->
  ((roundToIntegral ieee_float.RoundingMode.RNA x) =
   (roundToIntegral ieee_float.RoundingMode.RTP x)).
Proof.
  intros x h h'.
  destruct x; try easy.
  set (x:=(B754_finite s m e e0)); fold x in h, h'.
  assert (forall m', is_finite (roundToIntegral m' x)) as h1 by
        (intro m'; apply roundToIntegral_finite; easy).
  apply to_real_refl; auto.
  2: apply same_sign_roundToIntegral2; easy.
  apply eq_sym, eq_diff_floor_ceil in h.

  rewrite to_real_roundToIntegral, to_real_roundToIntegral; try easy.
  f_equal.
  unfold to_int.
  fold (to_real x).

  destruct (is_int_or_not x).
  rewrite (int_to_real RTZ _ H).
  destruct (valid_rnd_round_mode RNA) as (_,H').
  simpl in H'.
  rewrite H', Zceil_IZR; reflexivity.

  unfold Znearest.
  rewrite Rcompare_Eq.
  rewrite Zle_bool_true; auto.
  apply non_zero_positive_to_real in h'; try easy.
  apply Zfloor_lub.
  lra.
  unfold is_zero.
  unfold eq. simpl.
  now destruct s.

  rewrite Zceil_floor_neq in h.
  rewrite plus_IZR in h.
  lra.

  unfold is_int in H.
  apply Decidable.not_and in H.
  destruct H.
  now elim H.
  now apply not_eq_sym.
  now left.
Qed.

(* Why3 goal *)
Lemma to_int_roundToIntegral :
  forall (m:ieee_float.RoundingMode.mode) (x:t),
  ((to_int m x) = (to_int m (roundToIntegral m x))).
Proof.
  intros m x.
  destruct x; try easy.
  unfold to_int at 2.
  rewrite to_real_roundToIntegral by easy.
  destruct (valid_rnd_round_mode m) as (_,h).
  pose proof (h (to_int m (B754_finite s m0 e e0))).
  now destruct m.
Qed.

(* Why3 goal *)
Lemma to_int_monotonic :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t), is_finite x ->
  is_finite y -> le x y -> ((to_int m x) <= (to_int m y))%Z.
Proof.
intros m x y h1 h2 h3.
now apply to_int_le.
Qed.

(* Why3 goal *)
Lemma to_int_of_int :
  forall (m:ieee_float.RoundingMode.mode) (i:Numbers.BinNums.Z),
  in_safe_int_range i -> ((to_int m (of_int m i)) = i).
Proof.
intros m i (h1,h2).
apply eq_IZR.
rewrite <-int_to_real.
rewrite of_int_to_real.
apply Exact_rounding_for_integers; auto.
unfold in_safe_int_range; auto.
apply Bounded_real_no_overflow, rep_int_in_range; auto.
apply of_int_is_int.
pose proof pow2sb_lt_max_int.
unfold in_int_range; auto with zarith.
Qed.

(* Why3 goal *)
Lemma eq_to_int :
  forall (m:ieee_float.RoundingMode.mode) (x:t) (y:t), is_finite x ->
  eq x y -> ((to_int m x) = (to_int m y)).
Proof.
intros m x y h1 h2.
apply to_int_eq, h2.
Qed.

(* Why3 goal *)
Lemma neg_to_int :
  forall (m:ieee_float.RoundingMode.mode) (x:t), is_int x ->
  ((to_int m (neg x)) = (-(to_int m x))%Z).
Proof.
intros m x h1.
apply neg_int_to_int; auto.
Qed.

(* Why3 goal *)
Lemma roundToIntegral_is_finite :
  forall (m:ieee_float.RoundingMode.mode) (x:t), is_finite x ->
  is_finite (roundToIntegral m x).
Proof.
intros m x h1.
apply roundToIntegral_finite, h1.
Qed.

End GenericFloat.
