[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
point.


> 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
Equatable.

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