Float type that implements `Eq` in rust
Asked Answered
C

2

7

In rust, is there a version of f32 / f64 that implements Eq?
The only reason I can see for f32 / f64 not implementing Eq is that NaN != NaN.
Potential ways such a type could behave:

  1. The type could just make NaN == NaN for that type which would be really useful because I often assume that a == a is always true.
  2. Another approach would be to disallow NaN entirely in that type so that there is no NaN that could be unequal to itself.

Ideally there would be a way to use that type just by using a suffix (similar to 2.3_f32) but I don't think that is possible.

Chon answered 18/8, 2022 at 20:50 Comment(2)
NaN isn't the only reason not to implement Eq. Comparing floating point numbers for equality is just not that useful in the first place: println!("{}", 0.1 + 0.2 == 0.3); prints false because of rounding errors and the decimal to binary conversions. Given that the PartialEq is already not that useful, it's not surprising no one would have bothered making a floating point type work with Eq.Parable
Rust internals forum: NonNan type discussion. Its not trivial to avoid NaNs on computers whose instructions can produce NaN for even "simple" operations, and APIs designed to avoid that would either be fraught with panics or fallible results for the caller to handle. You can see if crates like noisy-float or ordered-float suit your needs. You can of course make your own bespoke type wrapper that implements Eq with the specific behavior you desire.Amphisbaena
M
4

Since Rust 1.62.0, you can use the total_cmp() methods of f32 and f64. Not a type on their own, but you can build a type on top of them if you want.

Or you can use the ordered-float crate. It provides the NotNan and OrderedFloat types, each matching one behavior you described.

Malaya answered 11/8, 2023 at 5:47 Comment(0)
D
0

f64 and f32 cannot implement Eq, because of Rust's fundamental design mistake of making Eq a sub-type of PartialEq.

This means that despite the IEEE754 spec defining a total order for floating point values, there can only ever be a single implementation inside Rust's Eq-PartialEq hierarchy.

That implementation uses the comparison predicate (which is only a partial order), instead of the total-order predicate (which is a total order (and therefore a partial order as well)).

If Eq and PartialEq were unrelated, floating point types could implement both §5.10 for Eq and §5.11 for PartialEq – but because they aren't – Rust was forced to pick one, and it chose §5.11.

Dragon answered 3/10 at 14:25 Comment(2)
Eq and PartialEq having differing behaviors sounds like a nightmareAmphisbaena
That's largely a naming problem: Rust emphasized mathematical concepts over intended use. I picked the names Equality/Identity (and Comparable/Sortable for PartialOrd/Ord) in my language and everything just makes sense and works reliably, i. e. I can put floats (and structs containing floats) into lists and maps, and can look them up, with zero hassle involved.Dragon

© 2022 - 2024 — McMap. All rights reserved.