# Comparable and FloatingPoint types

**URL:** <https://forums.swift.org/t/comparable-and-floatingpoint-types/16886>\
**Category:** Pitches\
**Tags:** numerics\
**Created:** [October 11, 2018, 3:13am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886 "2018-10-11T03:13:38Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![scanon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/scanon/32/2445_2.png) [@scanon](https://forums.swift.org/u/scanon)\
**Post date:** [October 11, 2018, 3:13am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/1 "2018-10-11T03:13:38Z")

</div>

## Background: Comparable and Equatable vs. IEEE 754

The `Comparable` and `Equatable` protocols want to imply a total order. This is _mostly_ satisfied by `FloatingPoint` types, except for the behavior with NaNs. A total order requires that for any a and b, either a ≤ b or a ≥ b is true. But IEEE 754 requires that if either a or b is NaN, both of those comparisons are false.

## Why Do We Care

Aside from mathematical purity, there's some highly undesirable behavior that results from the current behavior of API that depends on Comparable and Equatable with floating-point values. Some examples of misbehavior:

```swift
> let foo = [2.0, .nan, 1.0].sorted()
foo: [Double] = 3 values {
  [0] = 2
  [1] = NaN
  [2] = 1
}
> foo.contains(.nan)
$R0: Bool = false

```

Obviously, these results are quite counterintuitive and likely to cause bugs for unsuspecting users.

## Proposed Remedy

Use the `@_implements` feature to make it so the comparison operators yield a total order on floating-point data when used in a generic context constrained only to `Comparable` or `Equatable`. When the comparison operators are used in a concrete context, or in a generic context constrained more tightly than `Comparable` (e.g. an algorithm generic over `FloatingPoint`), they should continue to have the current (IEEE 754) behavior.

### Details

On `FloatingPoint`, `BinaryFloatingPoint`, and the concrete floating point types, the operators would continue to work as they currently do. When constrained only to Comparable or Equatable, we would use the following implementations instead:

```swift
@implements(Equatable,==(_:_:))
static func _totalEquals(lhs: Self, rhs: Self) -> Bool {
  // Normal equality, except all NaNs compare equal to each other.
  return lhs == rhs || lhs.isNaN && rhs.isNaN
}

@implements(Comparable,<(_:_:))
static func _totalLess(lhs: Self, rhs: Self) -> Bool {
  // Normal less than, except NaN ordered below everything else.
  return lhs < rhs || lhs.isNaN && !rhs.isNaN
}

@implements(Comparable,<=(_:_:))
static func _totalLessEqual(lhs: Self, rhs: Self) -> Bool {
  // Normal less-equals, except NaN ordered below everything else.
  return lhs <= rhs || lhs.isNaN
}

```

We would also need to modify hashing for FloatingPoint numbers to hash all NaNs to the same value; this is simple and involves only a well-predicted branch for most use.

### Benefits

1. API on Comparable and Equatable is much better behaved; the defaults Just Work.
2. Floating point algorithms ported from other languages Just Works, because in such a context you still get the IEEE 754 comparisons.
3. No performance penalty for the most common operations (concrete comparisons), very slight performance penalty for the comparisons that we replace.

### Drawbacks

1. It's surprising to have a basic operator behave differently in a concrete or generic context. I personally believe that it's OK here, because users don't write a lot of generic code against `Comparable`; rather they will the existing APIs that depend on it. So all that most users see is that those APIs now give more sensible answers. Users writing code against more specific protocols would see no change in behavior.
2. Very small performance penalty. I think that's ok in the name of getting a sensible answer.
3. It isn't quite possible to do this yet. An implementation is blocked by ([[SR-8961] @\_implements still not quite powerful enough · Issue #51466 · swiftlang/swift · GitHub](https://bugs.swift.org/browse/SR-8961))

## Alternatives Considered

1. OMG Floating-point is broken, make `<` and `==` do the right thing.  
Source breaking, and also breaks everyone's expectations coming from almost any other language. A non-starter. Contrary to many people's belief, this would _not_ be a violation of IEEE 754; the standard says "you have to have an operation with these semantics", but does not specify how it needs to be spelled in source code.

2. Use the IEEE 754 totalOrder predicate.  
Unfortunately, this is really a totalOrder on canonical encodings, rather than numeric values. Doing this would lead to behavior just as confusing, in the presence of redundant encodings:

```swift
> [-0.0].contains(0)
$R0: Bool = false
> [20.0 as Decimal64].contains(2.0e1) // hypothetical IEEE decimal type
$R1: Bool = false

```

This predicate was well-intentioned by the 754 committee, but the semantics are totally wrong for our purposes.

1. Do nothing.  
I guess. The world hasn't quite caught fire yet.

## Additional Notes

We should simultaneously deprecate the legacy `isEqual(to:)`, `isLess(than:)` and `isLessThanOrEqualTo(:)` methods on FloatingPoint. These were originally added because we didn't yet have static operators, and they're occasionally useful as hooks, but the implementation of`FloatingPoint` comparisons should be made consistent with `BinaryInteger` where we can, and have the operators be the primary thing.

We should consider introducing an intermediate protocol that refines `Numeric` and is refined by both `BinaryInteger` and `FloatingPoint`, which would be `Numeric + Comparable`. As a straw man, I would call it `OrderedNumeric`. _On it's own_, this doesn't enable any new generic code to be written, but in the presence of `@_implements` it can. This would be the protocol that abstracts over floating-point and integer, but where floating-point comparisons still have IEEE 754 semantics. I know that Xiaodi has needed to be able to describe this at some point in the past.

---

<div class="post-metadata">

**Author:** ![scanon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/scanon/32/2445_2.png) [@scanon](https://forums.swift.org/u/scanon)\
**Post date:** [October 11, 2018, 3:18am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/2 "2018-10-11T03:18:36Z")

</div>

There's been a lot of past discussion around this issue:

> [@\[pitch\] Comparison Reform](https://forums.swift.org/t/pitch-comparison-reform/5662):
>
> Hi swift evolution, Here’s another pitch, for The Propoosal Formerly Known As Spaceship. Comparison Reform Proposal: SE-NNNN \<file:///Users/ben\_cohen/Documents/swift-evolution/proposals/NNNN-filename.md\> Authors: Robert Widmann \<[https://github.com/codafi&gt;](https://github.com/codafi&gt;), Jaden Geller \<[https://github.com/jadengeller&gt;](https://github.com/jadengeller&gt;), Harlan Haskins \<[https://github.com/harlanhaskins&gt;](https://github.com/harlanhaskins&gt;), Alexis Beingessner \<[https://github.com/Gankro&gt;](https://github.com/Gankro&gt;), Ben Cohen \<[https://github.com/airspeedswift&gt](https://github.com/airspeedswift&gt); Status: Awaiting review Review …

> [@Rationalizing FloatingPoint conformance to Equatable](https://forums.swift.org/t/rationalizing-floatingpoint-conformance-to-equatable/6861):
>
> Ben Cohen asked to continue this conversation on swift-dev-- Included in PR #12503 is a small tweak to accommodate so-called "exceptional values" (such as NaN) in comparisons of array equality. Currently, `Array.==` first looks to referential equality of underlying buffers, then (if false) compares elementwise equivalence as defined by `Element.==`. As a consequence, an array of NaN compares equal to another array of NaN if they share the same buffer, but otherwise false. This is an undes…

> [@\[Proposal\] Formalized Ordering, take 2](https://forums.swift.org/t/proposal-formalized-ordering-take-2/3540):
>
> Since we're running short on time, and the previous discussion thread diverged, here's my attempt to fix the Comparable protocol. Pull request: [Formalized ordering by pyrtsa · Pull Request #464 · apple/swift-evolution · GitHub](https://github.com/apple/swift-evolution/pull/464) TL;DR: 1. Equatable remains unchanged, while Comparable bloats a bit to support several use cases. 2. `a \<=\> b` is well-defined even if either value is NaN. Zero is equal to minus zero. 3. Types are not strictly required to become totally ordered, even if it's strongl…

> [@\[Idea\] Bringing the partial/total ordering distinction into Comparable](https://forums.swift.org/t/idea-bringing-the-partial-total-ordering-distinction-into-comparable/2322):
>
> Currently, Comparable looks like this: &nbsp;&nbsp;public protocol Comparable : Equatable { &nbsp;&nbsp;&nbsp;&nbsp;/// A [strict total order]([Total order - Wikipedia](http://en.wikipedia.org/wiki/Total_order#Strict_total_order%5C)) &nbsp;&nbsp;&nbsp;&nbsp;/// over instances of `Self`. &nbsp;&nbsp;&nbsp;&nbsp;@warn\_unused\_result &nbsp;&nbsp;&nbsp;&nbsp;func \< (lhs: Self, rhs: Self) -\> Bool &nbsp;&nbsp;&nbsp;&nbsp;@warn\_unused\_result &nbsp;&nbsp;&nbsp;&nbsp;func \<= (lhs: Self, rhs: Self) -\> Bool &nbsp;&nbsp;&nbsp;&nbsp;@warn\_unused\_result &nbsp;&nbsp;&nbsp;&nbsp;func \>= (lhs: Self, rhs: Self) -\> Bool &nbsp;&nbsp;&nbsp;&nbsp;@warn\_unused\_result &nbsp;&nbsp;&nbsp;&nbsp;func \> (lhs: Self, rhs: Self) -\> Bool &nbsp;&nbsp;} Simple and straightforward, but not actually …

I'm probably missing a few more.

What's different now? Mostly, that we actually (almost) have the machinery in place to build a relatively simple solution. We didn't before.

This proposal is also significantly more narrowly targeted than previous attempts have been. It's not a big sweeping language change. If you squint, you can almost pretend that we're just fixing the behaviors of a few APIs where they currently have bogus behavior. Obviously, it's actually a bigger change than that, but from the perspective of most user's experience of it, that's about the scope of it.

As a personal note, I'll be on vacation for the next two weeks. Some other folks from the standard library team will be helping with this pitch, but if there are specific IEEE 754 questions that I need to respond to, the latency will be longer than usual. Nonetheless, I'd like to start discussion of this so that we can make the change for Swift 5 if we decide to pursue it.

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [October 11, 2018, 3:26am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/3 "2018-10-11T03:26:26Z")

</div>

> [@scanon](#):
>
> We should consider introducing an intermediate protocol that refines `Numeric` and is refined by both `BinaryInteger` and `FloatingPoint` , which would be `Numeric + Comparable` . As a straw man, I would call it `OrderedNumeric` . _On it's own_ , this doesn't enable any new generic code to be written, but in the presence of `@_implements` it can. This would be the protocol that abstracts over floating-point and integer, but where floating-point comparisons still have IEEE 754 semantics. I know that Xiaodi has needed to be able to describe this at some point in the past.

If the overall scheme were to be adopted, such an addition might be useful but I rather think it would be reasonable for Numeric.== to have IEEE semantics.

---

<div class="post-metadata">

**Author:** ![scanon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/scanon/32/2445_2.png) [@scanon](https://forums.swift.org/u/scanon)\
**Post date:** [October 11, 2018, 3:27am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/4 "2018-10-11T03:27:31Z")

</div>

Yes, I think that's fine. My concern was mainly for your use w.r.t. `Comparable`, since `Numeric` does not conform.

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [October 11, 2018, 3:31am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/5 "2018-10-11T03:31:02Z")

</div>

Right, there are certainly advantages to adding such a protocol but I think a side benefit of Numeric not conforming to Comparable (in addition to accommodating complex numbers) is that we can sidestep the issue here with respect to \< and \> rather cleanly (by which I mean that there's only Comparable.\< and FloatingPoint.\< with no question of what the semantics of the operator would be on an intermediate protocol).

---

<div class="post-metadata">

**Author:** ![gwynne](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/gwynne/32/24337_2.png) [@gwynne](https://forums.swift.org/u/gwynne)\
**Post date:** [October 11, 2018, 3:35am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/6 "2018-10-11T03:35:02Z")

</div>

I agree strongly that we need a solution, but I'm _very_ reluctant to go with making operators behave differently in generic vs. concrete context. People will inevitably run into the difference, even if not on a day-to-day basis. There will be a lot of "if I do X my code works but not if I do Y" issues as developers who don't understand the fundamental design issues of floating-point in general assume the language is to blame - in other words, what we have now but with a few extra points of confusion.

---

<div class="post-metadata">

**Author:** ![scanon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/scanon/32/2445_2.png) [@scanon](https://forums.swift.org/u/scanon)\
**Post date:** [October 11, 2018, 3:38am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/7 "2018-10-11T03:38:49Z")

</div>

> [@gwynne](#):
>
> I agree strongly that we need a solution, but I'm _very_ reluctant to go with making operators behave differently in generic vs. concrete context.

I'm sympathetic to that line of argument (that's why I highlighted it), and I agree that it feels icky, but ... in this _specific_ case, it's relatively hard to imagine a scenario in which it would actually come up. It will certainly be less common than `[Float].contains(.nan)`, for example.

---

<div class="post-metadata">

**Author:** ![Paul\_Cantrell](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/paul_cantrell/32/16764_2.png) [@Paul\_Cantrell](https://forums.swift.org/u/Paul_Cantrell)\
**Post date:** [October 11, 2018, 3:42am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/8 "2018-10-11T03:42:44Z")

</div>

> [@scanon](#):
>
> It's surprising to have a basic operator behave differently in a concrete or generic context.

My gut reaction is that this is a showstopper. The bugs it would produce, though rare, would be insidious — and there would be no compiler help in flagging them.

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [October 11, 2018, 3:43am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/9 "2018-10-11T03:43:34Z")

</div>

> [@scanon](#):
>
> I'm sympathetic to that line of argument (that's why I highlighted it), and I agree that it feels icky, but ... in this _specific_ case, it's relatively hard to imagine a scenario in which it would actually come up. It will certainly be less common than `[Float].contains(.nan)` , for example.

Likewise, I was once quite opposed to this proposed design for the ickiness factor, but I've come around to believe that this is probably the only workable solution. One should also mention, perhaps, that it's not unprecedented; I believe Kotlin also adopts the same design.

> [@Paul\_Cantrell](#):
>
> My gut reaction is that this is a showstopper. The bugs it would produce, though rare, would be insidious — and there would be no compiler help in flagging them.

It's no different than concrete methods shadowing protocol extension methods, which Swift freely allows. In that sense, though icky, one might say it's also Swifty.

---

<div class="post-metadata">

**Author:** ![scanon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/scanon/32/2445_2.png) [@scanon](https://forums.swift.org/u/scanon)\
**Post date:** [October 11, 2018, 3:47am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/10 "2018-10-11T03:47:37Z")

</div>

> [@Paul\_Cantrell](#):
>
> My gut reaction is that this is a showstopper. The bugs it would produce, though rare, would be insidious — and there would be no compiler help in flagging them.

There's also no compiler help flagging the bugs we have _today_, and they're much, much, easier to back into, because you end up there without writing any generic code of your own.

With the proposal, the way you would end up in the bad state would be to have code generic over `Comparable` or `Equatable`, and other code on concrete types or `FloatingPoint`, and somehow have a requirement that they produce the same result. That's a pretty weird situation though, because the algorithms that you write against `Comparable` are fundamentally different from the algorithms that you write against the `FloatingPoint` protocol or types, because they have a totally different API surface.

I would also point out that this subject has been actively discussed off-and-on for over three years by some very clever people, and so far no one has come up with a clearly better solution. That's not to say that it's impossible, just that it's not easy.

---

<div class="post-metadata">

**Author:** ![jawbroken](https://avatars.discourse-cdn.com/v4/letter/j/cc9497/32.png) [@jawbroken](https://forums.swift.org/u/jawbroken)\
**Post date:** [October 11, 2018, 3:50am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/11 "2018-10-11T03:50:43Z")

</div>

I agree. You are much more likely to encounter the bugs that this proposal is designed to address than the ones it will theoretically introduce. So it seems like an easy choice to take the insidious bugs that are less likely to occur than the insidious bugs that are more likely to occur, given the option.

---

<div class="post-metadata">

**Author:** ![gwynne](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/gwynne/32/24337_2.png) [@gwynne](https://forums.swift.org/u/gwynne)\
**Post date:** [October 11, 2018, 3:58am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/12 "2018-10-11T03:58:19Z")

</div>

Okay, I admit, that's a good point - consider me convinced that this is a valid solution 🙂

---

<div class="post-metadata">

**Author:** ![Paul\_Cantrell](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/paul_cantrell/32/16764_2.png) [@Paul\_Cantrell](https://forums.swift.org/u/Paul_Cantrell)\
**Post date:** [October 11, 2018, 4:21am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/13 "2018-10-11T04:21:33Z")

</div>

> [@scanon](#):
>
> With the proposal, the way you would end up in the bad state would be to have code generic over `Comparable` or `Equatable` , and other code on concrete types or `FloatingPoint` , and somehow have a requirement that they produce the same result.

It’s not so hard to imagine a context where the developer assumes `>` is consistent with `sorted()`:

```
// Iterating over all nums ≤ max in sorted order:
for n in nums.sorted() { // Sorting using Comparable behavior, NaNs come first
    guard n < max else { // Wrongly assuming > is consistent with sorted()...
        return // ...we ignore all elements if nums contains a NaN
    }
    ...
}

```

Granted, this code is also broken under the current misbehavior of `sorted()`! But this proposed solution feels like a game of illogic whack-a-mole.

I’ll also grant there’s not an obvious better solution.

The strictly correct one would be not to let `Float` implement `Comparable` at all, and instead have a separate `OrderedFloat` wrapper. The attendant conversion nuisance and source impact is probably a deal-killer for that.

I’m also tempted to propose an IEEE-compliant `&>` for `Float`, in the spirit of `&+` for Int. I can see that the existing source impact of that is probably not acceptable. It is worth considering, however, Swift’s precedent here: when translating code from other languages, one does have to consider whether to use `+` or `&+` — and the operator that gives the more familiar behavior is the weird-looking one, not the default `+`.

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [October 11, 2018, 4:40am UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/14 "2018-10-11T04:40:01Z")

</div>

> [@Paul\_Cantrell](#):
>
> It’s not so hard to imagine a context where the developer assumes `>` is consistent with `sorted()` :
> 
> ```swift
> // Iterating over all nums ≤ max in sorted order:
> for n in nums.sorted() { // Sorting using Comparable behavior, NaNs come first
> guard n < max else { // Wrongly assuming > is consistent with sorted()...
> return // ...we ignore all elements if nums contains a NaN
> }
> ...
> }
> 
> ```
> 
> Granted, this code is also broken under the current misbehavior of `sorted()` ! But this proposed solution feels like a game of illogic whack-a-mole.
> 
> I’ll also grant there’s not an obvious better solution.

What's nice, at least, is that with the proposed change this is likely to be immediately obvious as either all elements are ignored or the code works correctly (depending on whether we decide NaN is greater than or less than everything), nothing in between. Today, there are no semantic guarantees as to what the result might be.

---

<div class="post-metadata">

**Author:** ![Joe\_Groff](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joe_groff/32/1929_2.png) [@Joe\_Groff](https://forums.swift.org/u/Joe_Groff)\
**Post date:** [October 11, 2018, 2:07pm UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/15 "2018-10-11T14:07:20Z")

</div>

Great to see movement on this again. This is a great way to pretty much completely solve the problem of floating point vs total comparison. I think you should make it clearer in your pitch, though, that the splitting point for the two interfaces sits _above_ `FloatingPoint` and `Integer` protocols. (You do mention this, but only near the end, by the time some people's panic reflex may already have triggered.) That was a sticking point in previous iterations of this discussion, and I think we should make it clear you're addressing it.

I think the main benefit of this proposal isn't so much that it allows floating point to be weird, but that it allows Equatable and Comparable to be completely normal—anyone writing generic code at that level can assume the expected identities hold and don't have to worry about edge cases introduced by floating-point behavior.

---

<div class="post-metadata">

**Author:** ![beccadax](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/beccadax/32/34217_2.png) [@beccadax](https://forums.swift.org/u/beccadax)\
**Post date:** [October 11, 2018, 3:02pm UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/16 "2018-10-11T15:02:38Z")

</div>

The only suggestion I’d make is to provide a way to access these versions of the operators even in a concrete context, instead of using underscored names. Otherwise, I think I’m for it.

---

<div class="post-metadata">

**Author:** ![Joe\_Groff](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joe_groff/32/1929_2.png) [@Joe\_Groff](https://forums.swift.org/u/Joe_Groff)\
**Post date:** [October 11, 2018, 3:15pm UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/17 "2018-10-11T15:15:10Z")

</div>

Yeah, eventually I think we want to have explicit syntax for "namespacing" declarations and references, which would supersede the need for `@_implements`, e.g.:

```swift
struct MyFloat {
  static func Equatable.==(l: MyFloat, r: MyFloat) -> Bool { /* total equality */ }
  static func Numeric.==(l: MyFloat, r: MyFloat) -> Bool { /* IEEE equality */ }
}

let totallyEqual = Equatable.==(x, y)
let floatallyEqual = Numeric.==(x, y)

```

---

<div class="post-metadata">

**Author:** ![nnnnnnnn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nnnnnnnn/32/264_2.png) [@nnnnnnnn](https://forums.swift.org/u/nnnnnnnn)\
**Post date:** [October 11, 2018, 3:33pm UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/18 "2018-10-11T15:33:42Z")

</div>

I think I'm in favor of this change, though it really could lead to some pretty confusing behavior. Am I right in this interpretation?

```swift
let numbers = [1.0, 2.0, 3.0, .nan]
let containsAnNaN = numbers.contains(.nan)
// containsAnNaN = true

var findAnNaN = false
for x in numbers {
    if x == .nan {
        findAnNaN = true
    }
}
// findAnNaN == false

```

Is there any way we can make direct comparisons to `.nan` warn, like we do with `as?` casts that always succeed? That won't take care of all cases, but could help folks who expect floating-point values to have the same semantics as other `Equatable` types.

---

<div class="post-metadata">

**Author:** ![nnnnnnnn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nnnnnnnn/32/264_2.png) [@nnnnnnnn](https://forums.swift.org/u/nnnnnnnn)\
**Post date:** [October 11, 2018, 3:39pm UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/19 "2018-10-11T15:39:44Z")

</div>

> [@beccadax](#):
>
> The only suggestion I’d make is to provide a way to access these versions of the operators even in a concrete context, instead of using underscored names. Otherwise, I think I’m for it.

We do have the `<=` operation, as (Keanu Reeves voice) `isTotallyOrdered(belowOrEqualTo:)`. It would be nice to have `isTotallyOrdered(below:)` and `isTotallyOrdered(equalTo:)` to match the more commonly required operations.

@scanon This brings to mind another question: What's the behavior of `numbers.sorted(by: >)`? Does the fact that I'm passing in the actual operator mean that I get the type-specific case instead of the `Comparable` conformance version? We don't have a way to say "sort in descending order", so there's an implicit promise that `sorted(by: >) == sorted().reversed()`. My hunch is that this change would break that, or more accurately, still fail to satisfy that expectation.

---

<div class="post-metadata">

**Author:** ![Nevin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nevin/32/617_2.png) [@Nevin](https://forums.swift.org/u/Nevin)\
**Post date:** [October 11, 2018, 4:04pm UTC](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886/20 "2018-10-11T16:04:05Z")

</div>

I think we should give more serious consideration to switching IEEE-754 semantics over to “`&`”-prefixed comparison operators. This would put them better in line with integers, where the wrapping arithmetic found in other languages requires an ampersand to access in Swift.

Note that with integers it only makes a difference which operator you choose when overflow occurs, and similarly with floating-point it only makes a difference when NaN is involved.

In fact, to put integers and floats on equal footing, it might even makes sense to have the standard comparison operators \*trap\* when they encounter NaN. If that is too inconvenient when sorting though, then the proposed “NaN is less than everything else” would work.

Yes, introducing the “`&`”-comparison operators will be source-breaking. However, the migration will be automatable by simply inserting an ampersand wherever the types are statically known to conform to `FloatingPoint`, so concrete code will perform exactly the same.

Generic code will change in exactly the same way as is being proposed in this thread, so when considering the two options there is no difference between them here. They are both equally source-breaking (or source-fixing as the case may be).

The major difference is consistency: IEEE-754 comparisons will always begin with an ampersand, and `Comparable` ones will always have their usual spelling.

[Next page](https://forums.swift.org/t/comparable-and-floatingpoint-types/16886.md?page=2)
