[swift-dev] Rationalizing FloatingPoint conformance to Equatable

Xiaodi Wu xiaodi.wu at gmail.com
Sun Oct 29 21:34:04 CDT 2017

On Fri, Oct 27, 2017 at 5:06 AM, Jonathan Hull <jhull at gbis.com> wrote:

> On Oct 26, 2017, at 11:44 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
> On Fri, Oct 27, 2017 at 1:30 AM, Jonathan Hull <jhull at gbis.com> wrote:
>> One completely different idea, which I brought up a year or so ago, is to
>> do what we do with pointers around this.  That is you have your fast/unsafe
>> IEEE Floats/Doubles/etc that have a scarier name.  These do not conform to
>> Equatable or Comparable, but have their own version of IEEE
>> equality/comparison. Let’s spell it &== and &< to make it feel different so
>> the users consider the possibility of NaN.  They don’t have any notion of
>> hashability.
> As I wrote in my reply to Greg, IEEE equality and comparison is _the_ best
> approximation of mathematical equality and comparison suitable for
> floating-point types. If another one were superior, then floating-point
> experts would have designated that as the standard.
> We definitely have different world views.  I see the handling of NaN as a
> legacy/compatibility issue due to committee/vendor politics from the
> 1980’s.  I am pretty sure if they could do it over with modern tech, we
> would just have isNan() and NaN == NaN… or we might just have optionals
> instead.
> Just to play devil’s advocate, there are actually much better and more
> accurate representations available using the same number of bits.  The main
> issue is that there isn’t common hardware support for them.  That is not
> what I am suggesting here however.
> Swift correctly exposes only one concept of equality for floating-point
> types. It is and should be IEEE equality. People should be encouraged and
> not scared to use it. NaN is and should continue to exist as a concept.
> Yes, IEEE-compliant floating point is hard; the only thing harder than
> IEEE-compliant floating point is non-IEEE-compliant floating point.
> What I am suggesting is identical to IEEE in every way except for NaN.

The most recent edition of IEEE 754 is 70 pages long and mentions NaN on 40
of them. What you suggest is not an IEEE-compliant design for floating

> It is just an IEEE value that has been filtered so that we can guarantee
> it isn’t NaN. It still uses all the same hardware instructions.  Basically,
> it semantically converts NaN to nil… and that lets us conform to
> Equatable/Comparable honestly.  It also still technically adheres to IEEE…
> it just never comes up because we are careful to filter/handle NaN before
> the user ever has to deal with it.
> If you want/need to use NaN for some reason, you still have the IEEE
> types. What you can’t do is use them generically for ==.
> Can you give me an example of where you would want NaN in a generic
> context (that might also contain Ints), but an optional Float (which had
> been filtered not to have NaN) wouldn’t meet your needs?  Remember, this is
> a generic context, not one that is special casing Floats.

I'm not sure I understand the question. If you've already filtered out NaN
values, then you wouldn't have any NaN values, so why would you need a
generic algorithm that handles NaN?

> This thread is meant to discuss how to reconcile this scenario with the
> semantics of Equatable.
> Yes it is… and this is one possible approach to doing it.  We make it so
> Floats just don’t conform to Equatable, but we make a wrapper type that
> does conform (and can fully meet the guarantees).
> Then you have your safe/friendly Swift Floating point type(s) which just
>> have no concept of NaN at all (and probably a single notion of zero). You
>> have a failable initializer from the IEEE versions. These types conform to
>> Equatable/Hashable/Comparable.  Care is taken with internal methods so
>> that NaN can’t creep into the type.
>> How do we handle math functions which might fail?  We do the same thing
>> we do in the rest of Swift... those functions return an optional.
>> When reading in data from the outside world or C code, you would use the
>> IEEE versions and then either convert or do your calculations directly.
>> They would probably also be used for things like accelerate.  But most
>> code, where the values come from user input or literals, would never even
>> have to touch the IEEE version.
>> The advantage here is that you get full speed all the time, even in
>> generic contexts.  You just can’t use the IEEE versions directly in generic
>> contexts. You would have to convert them, which is a one-time cost (or use
>> them non-generically).
> Again, generics and protocol-based numerics are important; that's what
> Numeric is all about. Any idea that doesn't make this possible is a
> non-starter.
> Why is everything “impossible” or a “non-starter”?

To have a focused discussion, we have to define the givens and the task to
be accomplished. Here, the given constraint is that Swift floating point
types are IEEE-compliant and conform to Equatable. The task is to design

The wrapper version would adhere to Numeric and would be fully usable in
> generic contexts.  You can wrap the IEEE Floats, and the NaNs get converted
> to optionals, where you can apply the generic algorithm.  If your “generic”
> algorithm was depending on the bit representation of NaN or the fact that
> it breaks ==, then I would argue you really don’t want a generic algorithm
> after all… you have a Float specific algorithm.
> Also, in terms of speed, we should find something with the semantics we
> want (that should be the main focus of our discussion)… and then we can
> figure out how to tweak it so it goes as fast as we need it to once we know
> what we are aiming for.  Anything else is premature optimization.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-dev/attachments/20171029/a4db9bb8/attachment.html>

More information about the swift-dev mailing list