Zulip Chat Archive
Stream: lean4
Topic: DecidableEq for Float?
Geoffrey Irving (Jan 06 2024 at 20:08):
It looks like Float
doesn't have a DecidableEq
instance. Is that right, and is it intentional if so? I realize it can't have LawfulBEq
due to NaN, but that doesn't seem like it should block DecidableEq
.
Geoffrey Irving (Jan 06 2024 at 20:19):
I suppose it would be easy to accidentally use =
instead of ==
if DecidableEq
existed, with resulting different behavior.
Ruben Van de Velde (Jan 06 2024 at 20:44):
If it did, it would have to NaN = NaN
, right?
Geoffrey Irving (Jan 06 2024 at 20:44):
Yes, by rfl
.
Eric Wieser (Jan 06 2024 at 20:53):
DecidableEq
is impossible for Float because you can't prove anything at all about float
Geoffrey Irving (Jan 06 2024 at 20:54):
https://leanprover-community.github.io/mathlib4_docs/Init/Data/Float.html#Float.decLt
Geoffrey Irving (Jan 06 2024 at 20:54):
Are you thinking of Lean 3?
Eric Wieser (Jan 06 2024 at 20:54):
Oh, I guess that's not quite true; you can prove everything that's in docs#FloatSpec
Eric Wieser (Jan 06 2024 at 20:56):
So it is indeed weird that DecidableEq
is not in that structure, when everything else is
Geoffrey Irving (Jan 06 2024 at 20:57):
I think the foot canon of =
vs. ==
when writing Float
code might explain it. I think it may be weird formally but not weird in practice because of that.
Henrik Böving (Jan 06 2024 at 20:58):
Geoffrey Irving said:
I think the foot canon of
=
vs.==
when writingFloat
code might explain it. I think it may be weird formally but not weird in practice because of that.
But how would you treat the NaN case? NaN is not supposed to be equal to itself.
Eric Wieser (Jan 06 2024 at 20:58):
Sure, but plenty of languages fail at that anyway
Geoffrey Irving (Jan 06 2024 at 20:58):
We're not talking about changing any semantics: it has to be true that NaN = NaN
and NaN != NaN
.
Geoffrey Irving (Jan 06 2024 at 20:59):
And it is also true as a meta-mathematical fact that =
is decidable over Float
.
Geoffrey Irving (Jan 06 2024 at 20:59):
The only question is whether to make that fact available to programmers.
Eric Wieser (Jan 06 2024 at 21:00):
Eric Wieser said:
Sure, but plenty of languages fail at that anyway
To elaborate, python has a stronger version of ==
that sometimes surfaces from behind the scenes:
>>> nan = float('nan')
>>> d = {nan: 'oh no'}
>>> d[nan]
'oh no'
>>> d[float('nan')]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: nan
>>>
Eric Wieser (Jan 06 2024 at 21:01):
If we want to guard against the =
footgun on floats, that presumably can be handled by a linter; I don't think it is useful to cripple the =
notation (by making it need open Classical
, as it does today)
Eric Wieser (Jan 06 2024 at 21:05):
Here's a hack in the meantime that avoids needing to change core:
import Mathlib.Logic.Basic
unsafe def instDecidableEqFloatStupid : DecidableEq Float := fun f g => if toString f == toString g then .isTrue lcProof else .isFalse lcProof
@[instance, implemented_by instDecidableEqFloatStupid]
opaque instDecidableEqFloat : DecidableEq Float := Classical.decEq _
Eric Wieser (Jan 06 2024 at 21:06):
(it would be great if https://github.com/pygments/pygments/pull/2618 could land so that unsafe
and opaque
got highlighted there...)
Geoffrey Irving (Jan 06 2024 at 21:07):
How does that work? I don't think Float.toString
is injective.
Geoffrey Irving (Jan 06 2024 at 21:09):
And of course, if we implement this, we do want the fast native version.
Eric Wieser (Jan 06 2024 at 21:13):
Geoffrey Irving said:
How does that work? I don't think
Float.toString
is injective.
Ah, I guess we're in trouble because of how many different NaN
s there are, which indeed share a toString
.
Geoffrey Irving (Jan 06 2024 at 21:14):
Well, that's one problem...
#eval (1e-10 : Float).toString
-- "0.000000"
Eric Wieser (Jan 06 2024 at 21:17):
Oh, I naively assumed that Lean would be using something like dragon4 for unambiguous (finite) float printing like NumPy does
Geoffrey Irving (Jan 06 2024 at 21:18):
That would be better, I agree. Though unrelated to DecidableEq
which maps to a single assembly instruction.
Geoffrey Irving (Jan 06 2024 at 21:18):
I would certainly prefer it if 1e-10
didn't show up as 0, as it makes unit tests slightly harder to debug.
Eric Wieser (Jan 06 2024 at 21:19):
At risk of further derailment; is there any builtin way to print 1e-10
at higher precision?
Geoffrey Irving (Jan 06 2024 at 21:21):
printf("%.17g", x)
is (mostly) injective in C, so if we have access to format strings then yes.
Mario Carneiro (Jan 09 2024 at 02:30):
@Eric Wieser There is an implementation of toStringFull
either in zulip or in std (std4#282)
Mario Carneiro (Jan 09 2024 at 02:34):
My understanding of the lean model of Float is that it identifies all NaN
s (sign included) and otherwise distinguishes all bit patterns (including 0
vs -0
)
Last updated: May 02 2025 at 03:31 UTC