Module ExtFloats

From Flocq Require Import Binary.
Require Import Floats Integers ZArith Lia Bool.

Definition isfinitef1_mask := Z.shiftl ((two_p 8)-1) 23.

Definition fast_isfinitef1 (x : float32) :=
  negb (Int.eq (Int.and (Float32.to_bits x) (Int.repr isfinitef1_mask)) (Int.repr isfinitef1_mask)).

Lemma fast_isfinitef1_correct_bits: forall x, fast_isfinitef1 (Float32.of_bits x) = Binary.is_finite _ _ (Float32.of_bits x).
Proof.
  unfold fast_isfinitef1. intros.
  rewrite Float32.to_of_bits.
  Local Transparent Float32.of_bits.
  unfold Float32.of_bits.
  Local Opaque Float32.of_bits.
  unfold Bits.b32_of_bits.
  unfold Bits.binary_float_of_bits, Bits.binary_float_of_bits_aux.
  pose proof (Int.eq_spec (Int.and x (Int.repr isfinitef1_mask)) (Int.repr isfinitef1_mask)) as SPEC.
  symmetry.
  rewrite is_finite_FF2B.
  destruct (Bits.split_bits 23 8 (Int.unsigned x)) as [[s m] e] eqn:BITS.
  unfold Bits.split_bits in BITS.
  injection BITS. intros EXP MANTISSA SIGN. clear BITS.
  change (Z.pow_pos 2 23) with (two_p 23) in EXP.
  rewrite <- Zbits.Zshiftr_div_two_p in EXP by lia.
  change (Z.pow_pos 2 8) with (two_p 8) in EXP.
  rewrite <- Zbits.Zzero_ext_mod in EXP by lia.
  destruct Int.eq.
  {
    replace e with (2^ 8 - 1).
    { simpl. destruct m; reflexivity. }
    subst e.
    apply Zbits.equal_same_bits.
    intros.
    rewrite Zbits.Zzero_ext_spec by assumption.
    change (2 ^ 8) with (two_p 8).
    rewrite Zbits.Ztestbit_two_p_m1 by lia.
    destruct Coqlib.zlt. 2: reflexivity.
    rewrite Z.shiftr_spec by lia.
    fold (Int.testbit x (i+23)).
    assert(BIT : Int.testbit (Int.and x (Int.repr isfinitef1_mask)) (i+23) =
             (Int.testbit (Int.repr isfinitef1_mask)) (i+23))
      by(f_equal; assumption).
    rewrite Int.bits_and in BIT by (change Int.zwordsize with 32; lia).
    rewrite Int.testbit_repr in BIT by (change Int.zwordsize with 32; lia).
    unfold isfinitef1_mask in *.
    rewrite Z.shiftl_spec in BIT by lia.
    replace (i +23-23) with i in BIT by ring.
    rewrite Zbits.Ztestbit_two_p_m1 in BIT by lia.
    destruct (Coqlib.zlt i 8). 2: lia.
    rewrite andb_true_r in BIT.
    symmetry. assumption.
  }
  assert (NEQ: e <> 255).
  { change 255 with (two_p 8 - 1).
    intro. subst e.
    apply SPEC. clear SPEC.
    apply Int.same_bits_eq.
    intros.
    rewrite Int.bits_and by assumption.
    unfold isfinitef1_mask.
    rewrite Int.testbit_repr by assumption.
    rewrite Z.shiftl_spec by lia.
    destruct (Z_lt_le_dec i 23).
    { rewrite Z.testbit_neg_r by lia.
      apply andb_false_r. }
    assert(BIT : Z.testbit (Zbits.Zzero_ext 8 (Z.shiftr (Int.unsigned x) 23)) ( i - 23) = Z.testbit (two_p 8 - 1) (i - 23)) by (f_equal; assumption).
    rewrite Zbits.Zzero_ext_spec in BIT by lia.
    rewrite Z.shiftr_spec in BIT by lia.
    rewrite Zbits.Ztestbit_two_p_m1 in * by lia.
    replace (i - 23 +23) with i in BIT by ring.
    fold (Int.testbit x i) in BIT.
    destruct Coqlib.zlt.
    { rewrite andb_true_r. assumption. }
    apply andb_false_r.
  }
  pose proof (Zeq_bool_if e (2^8 - 1)) as BLAH.
  destruct Zeq_bool.
  { simpl in BLAH. lia. }
  clear BLAH.
  assert (0 <= m) as m_NONNEG.
  { rewrite <- MANTISSA.
    apply Z_mod_nonneg_nonneg.
    pose proof (Int.unsigned_range x). lia.
    change (Z.pow_pos 2 23) with (2^23). lia.
  }
  pose proof (Zeq_bool_if e 0) as BLAH.
  destruct Zeq_bool.
  { destruct m; trivial. lia.
  }
  assert (0 < m + 2^23) by lia.
  destruct (m + 2^23); trivial; lia.
Qed.

Theorem fast_isfinitef1_correct: forall x,
    fast_isfinitef1 x = Binary.is_finite _ _ x.
Proof.
  intro.
  rewrite <- (Float32.of_to_bits x).
  apply fast_isfinitef1_correct_bits.
Qed.

Definition isfinitef2_mask := (two_p 8) - 1.

Definition fast_isfinitef2 (x : float32) :=
  negb (Int.eq (Int.zero_ext 8 (Int.shru (Float32.to_bits x) (Int.repr 23))) (Int.repr isfinitef2_mask)).

Lemma fast_isfinitef2_correct_bits: forall x, fast_isfinitef2 (Float32.of_bits x) = Binary.is_finite _ _ (Float32.of_bits x).
Proof.
  unfold fast_isfinitef2. intros.
  rewrite Float32.to_of_bits.
  Local Transparent Float32.of_bits.
  unfold Float32.of_bits.
  Local Opaque Float32.of_bits.
  unfold Bits.b32_of_bits.
  unfold Bits.binary_float_of_bits, Bits.binary_float_of_bits_aux.
  pose proof (Int.eq_spec (Int.zero_ext 8 (Int.shru x (Int.repr 23)))
       (Int.repr isfinitef2_mask)) as SPEC.
  symmetry.
  rewrite is_finite_FF2B.
  destruct (Bits.split_bits 23 8 (Int.unsigned x)) as [[s m] e] eqn:BITS.
  unfold Bits.split_bits in BITS.
  injection BITS. intros EXP MANTISSA SIGN. clear BITS.
  change (Z.pow_pos 2 23) with (two_p 23) in EXP.
  rewrite <- Zbits.Zshiftr_div_two_p in EXP by lia.
  change (Z.pow_pos 2 8) with (two_p 8) in EXP.
  rewrite <- Zbits.Zzero_ext_mod in EXP by lia.
  destruct Int.eq.
  {
    replace e with (2^ 8 - 1).
    { destruct m; reflexivity. }
       
    subst e.
    apply Zbits.equal_same_bits.
    intros.
    rewrite Zbits.Zzero_ext_spec by assumption.
    change (2 ^ 8) with (two_p 8).
    rewrite Zbits.Ztestbit_two_p_m1 by lia.
    destruct Coqlib.zlt. 2: reflexivity.
    rewrite Z.shiftr_spec by lia.
    fold (Int.testbit x (i+23)).
    assert(BIT : Int.testbit (Int.zero_ext 8 (Int.shru x (Int.repr 23))) i =
             (Int.testbit (Int.repr isfinitef2_mask)) i)
      by(f_equal; assumption).
    rewrite Int.bits_zero_ext in BIT by (change Int.zwordsize with 32; lia).
    rewrite Int.testbit_repr in BIT by (change Int.zwordsize with 32; lia).
    unfold isfinitef2_mask in *.
    rewrite Int.bits_shru in BIT by (change Int.zwordsize with 32; lia).
    change (Int.unsigned (Int.repr 23)) with 23 in BIT.
    change Int.zwordsize with 32 in BIT.
    destruct Coqlib.zlt. 2: lia.
    rewrite Zbits.Ztestbit_two_p_m1 in BIT by lia.
    destruct (Coqlib.zlt i 8). 2: lia.
    destruct (Coqlib.zlt (i+23) 32). 2: lia.
    symmetry. assumption.
  }
  assert (NEQ: e <> 255).
  { change 255 with (two_p 8 - 1).
    intro. subst e.
    apply SPEC. clear SPEC.
    apply Int.same_bits_eq.
    intros.
    
    rewrite Int.bits_zero_ext by lia.
    unfold isfinitef2_mask.
    rewrite Int.testbit_repr by assumption.
    rewrite Int.bits_shru by lia.
    change (Int.unsigned (Int.repr 23)) with 23.
    change Int.zwordsize with 32.
    destruct (Z_lt_le_dec i 8).
    { destruct Coqlib.zlt. 2: lia.
      rewrite Zbits.Ztestbit_two_p_m1 by lia.
      destruct Coqlib.zlt. 2: lia.
      assert(BIT : Z.testbit (Zbits.Zzero_ext 8 (Z.shiftr (Int.unsigned x) 23)) i = Z.testbit (two_p 8 - 1) i) by (f_equal; assumption).
      rewrite Zbits.Zzero_ext_spec in BIT by lia.
      destruct Coqlib.zlt. 2: lia.
      rewrite Z.shiftr_spec in BIT by lia.
      rewrite Zbits.Ztestbit_two_p_m1 in * by lia.
      destruct Coqlib.zlt. 2: lia.
      assumption.
    }
    rewrite Zbits.Ztestbit_two_p_m1 by lia.
    destruct (Coqlib.zlt i 8). lia.
    reflexivity.
  }
  pose proof (Zeq_bool_if e (2^8 - 1)) as BLAH.
  destruct Zeq_bool.
  { simpl in BLAH. lia. }
  clear BLAH.
  assert (0 <= m) as m_NONNEG.
  { rewrite <- MANTISSA.
    apply Z_mod_nonneg_nonneg.
    pose proof (Int.unsigned_range x). lia.
    change (Z.pow_pos 2 23) with (2^23). lia.
  }
  pose proof (Zeq_bool_if e 0) as BLAH.
  destruct Zeq_bool.
  { destruct m; trivial. lia.
  }
  assert (0 < m + 2^23) by lia.
  destruct (m + 2^23); trivial; lia.
Qed.

Theorem fast_isfinitef2_correct: forall x,
    fast_isfinitef2 x = Binary.is_finite _ _ x.
Proof.
  intro.
  rewrite <- (Float32.of_to_bits x).
  apply fast_isfinitef2_correct_bits.
Qed.

Definition isfinite_mask := (two_p 11) - 1.

Definition fast_isfinite (x : float) :=
  negb (Int.eq (Int.zero_ext 11 (Int.shru (Int64.hiword (Float.to_bits x)) (Int.repr 20))) (Int.repr isfinite_mask)).

Lemma fast_isfinite_correct_bits: forall x, fast_isfinite (Float.of_bits x) = Binary.is_finite _ _ (Float.of_bits x).
Proof.
  unfold fast_isfinite. intros.
  rewrite Float.to_of_bits.
  Local Transparent Float.of_bits.
  unfold Float.of_bits.
  Local Opaque Float.of_bits.
  unfold Bits.b64_of_bits.
  unfold Bits.binary_float_of_bits, Bits.binary_float_of_bits_aux.
  pose proof (Int.eq_spec (Int.zero_ext 11 (Int.shru (Int64.hiword x) (Int.repr 20)))
       (Int.repr isfinite_mask)) as SPEC.
  symmetry.
  rewrite is_finite_FF2B.
  destruct (Bits.split_bits 52 11 (Int64.unsigned x)) as [[s m] e] eqn:BITS.
  unfold Bits.split_bits in BITS.
  injection BITS. intros EXP MANTISSA SIGN. clear BITS.
  change (Z.pow_pos 2 52) with (two_p 52) in EXP.
  rewrite <- Zbits.Zshiftr_div_two_p in EXP by lia.
  change (Z.pow_pos 2 11) with (two_p 11) in EXP.
  rewrite <- Zbits.Zzero_ext_mod in EXP by lia.
  destruct Int.eq.
  {
    replace e with (2^ 11 - 1).
    { destruct m; reflexivity. }
       
    subst e.
    apply Zbits.equal_same_bits.
    intros.
    rewrite Zbits.Zzero_ext_spec by assumption.
    change (2 ^ 11) with (two_p 11).
    rewrite Zbits.Ztestbit_two_p_m1 by lia.
    destruct Coqlib.zlt. 2: reflexivity.
    rewrite Z.shiftr_spec by lia.
    fold (Int64.testbit x (i+52)).
    assert(BIT : Int.testbit (Int.zero_ext 11 (Int.shru (Int64.hiword x) (Int.repr 20))) i =
             (Int.testbit (Int.repr isfinite_mask)) i)
      by(f_equal; assumption).
    rewrite Int.bits_zero_ext in BIT by (change Int.zwordsize with 32; lia).
    rewrite Int.testbit_repr in BIT by (change Int.zwordsize with 32; lia).
    unfold isfinite_mask in *.
    rewrite Int.bits_shru in BIT by (change Int.zwordsize with 32; lia).
    change (Int.unsigned (Int.repr 20)) with 20 in BIT.
    rewrite Int64.bits_hiword in BIT by (change Int.zwordsize with 32; lia).
    change Int.zwordsize with 32 in BIT.
    destruct Coqlib.zlt. 2: lia.
    rewrite Zbits.Ztestbit_two_p_m1 in BIT by lia.
    destruct (Coqlib.zlt i 11). 2: lia.
    destruct (Coqlib.zlt (i+20) 32). 2: lia.
    replace (i + 20 + 32) with (i + 52) in BIT by lia.
    symmetry. assumption.
  }
  assert (NEQ: e <> 2047).
  { change 2047 with (two_p 11 - 1).
    intro. subst e.
    apply SPEC. clear SPEC.
    apply Int.same_bits_eq.
    intros.
    
    rewrite Int.bits_zero_ext by lia.
    unfold isfinite_mask.
    rewrite Int.testbit_repr by assumption.
    rewrite Int.bits_shru by lia.
    change (Int.unsigned (Int.repr 20)) with 20.
    change Int.zwordsize with 32.
    destruct (Z_lt_le_dec i 11).
    { rewrite Int64.bits_hiword by (change Int.zwordsize with 32; lia).
      destruct Coqlib.zlt. 2: lia.
      rewrite Zbits.Ztestbit_two_p_m1 by lia.
      destruct Coqlib.zlt. 2: lia.
      assert(BIT : Z.testbit (Zbits.Zzero_ext 11 (Z.shiftr (Int64.unsigned x) 52)) i = Z.testbit (two_p 11 - 1) i) by (f_equal; assumption).
      rewrite Zbits.Zzero_ext_spec in BIT by lia.
      destruct Coqlib.zlt. 2: lia.
      rewrite Z.shiftr_spec in BIT by lia.
      rewrite Zbits.Ztestbit_two_p_m1 in * by lia.
      destruct Coqlib.zlt. 2: lia.
      change Int.zwordsize with 32.
      replace (i+20+32) with (i+52) by lia.
      assumption.
    }
    rewrite Zbits.Ztestbit_two_p_m1 by lia.
    destruct (Coqlib.zlt i 11). lia.
    reflexivity.
  }
  pose proof (Zeq_bool_if e (2^11 - 1)) as BLAH.
  destruct Zeq_bool.
  { simpl in BLAH. lia. }
  clear BLAH.
  assert (0 <= m) as m_NONNEG.
  { rewrite <- MANTISSA.
    apply Z_mod_nonneg_nonneg.
    pose proof (Int64.unsigned_range x). lia.
    change (Z.pow_pos 2 52) with (2^52). lia.
  }
  pose proof (Zeq_bool_if e 0) as BLAH.
  destruct Zeq_bool.
  { destruct m; trivial. lia.
  }
  assert (0 < m + 2^52) by lia.
  destruct (m + 2^52); trivial; lia.
Qed.

Theorem fast_isfinite_correct: forall x,
    fast_isfinite x = Binary.is_finite _ _ x.
Proof.
  intro.
  rewrite <- (Float.of_to_bits x).
  apply fast_isfinite_correct_bits.
Qed.