Skip to content

Commit 306adeb

Browse files
committed
feat: add beq definition and prove the infamous nan != nan
1 parent 95b4c22 commit 306adeb

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

Batteries/Data/Float/Axioms.lean

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ private structure Float.AxiomSet where
2424
isInf_def (x : Float) : x.isInf = (x.exponentPart = 2047 ∧ x.mantissa = 0)
2525
isFinite_def (x : Float) : x.isFinite = (x.exponentPart < 2047)
2626
neg_def (x : Float) : x.neg = ofBits (x.toBits ^^^ 0x8000_0000_0000_0000)
27+
beq_def (x y : Float) : x.beq y =
28+
if x.isNaN ∨ y.isNaN then false
29+
else if x.exponentPart = 0 ∧ x.mantissa = 0
30+
y.exponentPart = 0 ∧ y.mantissa = 0 then true
31+
else x.toBits = y.toBits
2732

2833
/--
2934
Auxiliary axiom redefining the opaque `Float` functions.
@@ -68,3 +73,19 @@ theorem Float.neg.eq_def (x : Float) :
6873
theorem Float.neg.eq_1 (x : Float) :
6974
x.neg = ofBits (x.toBits ^^^ 0x8000_0000_0000_0000) := by
7075
unfold Float.neg; rfl
76+
77+
theorem Float.beq.eq_def (x y : Float) :
78+
x.beq y =
79+
if x.isNaN ∨ y.isNaN then false
80+
else if x.exponentPart = 0 ∧ x.mantissa = 0
81+
y.exponentPart = 0 ∧ y.mantissa = 0 then true
82+
else x.toBits = y.toBits :=
83+
Float.definitionAxiom.beq_def x y
84+
85+
theorem Float.beq.eq_1 (x y : Float) :
86+
x.beq y =
87+
if x.isNaN ∨ y.isNaN then false
88+
else if x.exponentPart = 0 ∧ x.mantissa = 0
89+
y.exponentPart = 0 ∧ y.mantissa = 0 then true
90+
else x.toBits = y.toBits := by
91+
unfold beq; rfl

Batteries/Data/Float/Lemmas.lean

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ theorem Float.toBits_inj {x y : Float} : x.toBits = y.toBits ↔ x = y := by
1212
· rintro rfl
1313
rfl
1414

15+
-- not sure whether we want this
16+
-- `0 ≠ -0` but `nan = nan`
17+
instance : DecidableEq Float := fun _ _ =>
18+
decidable_of_decidable_of_iff Float.toBits_inj
19+
1520
example : (2047 <<< 52 ||| 2251799813685248) >>> 52 &&& 2047 = 2047 := by
1621
simp
1722

@@ -89,7 +94,29 @@ theorem Float.mantissa_neg (x : Float) : (-x).mantissa = x.mantissa := by
8994
simpa [isNaNBits, ← UInt64.toNat_inj, Nat.shiftRight_xor_distrib,
9095
Nat.and_xor_distrib_right] using h
9196

92-
-- not sure whether we want this
93-
-- `0 ≠ -0` but `nan = nan`
94-
instance : DecidableEq Float := fun _ _ =>
95-
decidable_of_decidable_of_iff Float.toBits_inj
97+
theorem Float.beq_def (x y : Float) : (x == y) = x.beq y := rfl
98+
99+
@[simp]
100+
theorem Float.not_nan_beq (x : Float) : (nan == x) = false := by
101+
rw [beq_def, beq]
102+
simp only [isNaN_nan, true_or, ↓reduceIte]
103+
104+
@[simp]
105+
theorem Float.not_beq_nan (x : Float) : (x == nan) = false := by
106+
rw [beq_def, beq]
107+
simp only [isNaN_nan, or_true, ↓reduceIte]
108+
109+
@[simp]
110+
theorem Float.beq_self_eq (x : Float) : (x == x) = decide (x ≠ nan) := by
111+
rw [beq_def, beq]
112+
simp [Float.isNaN_iff_eq_nan]
113+
114+
@[simp]
115+
theorem Float.beq_self_iff (x : Float) : x == x ↔ x ≠ nan := by
116+
simp
117+
118+
-- `a != b` is simplified to `!(a == b)` to ensure simp confluency
119+
@[simp]
120+
theorem Float.bne_eq_not_beq (x y : Float) : (x != y) = !(x == y) := rfl
121+
122+
example : Float.nan != Float.nan := by simp

0 commit comments

Comments
 (0)