I know of three functions for checking for equality:
isequal. The documentation comments on subtlety regarding floating point numbers, and there is indeed a difference:
julia> NaN == NaN
julia> isequal(NaN, NaN)
julia> NaN === NaN
Could you explain why they behave this way? I am particularly interested in
Why isequal was designed to behave differently from == for float numbers.
NaN === NaN is
true. For most other types, I would have naively assumed
a === b implies
Determine whether x and y are identical, in the sense that no program could distinguish them.
according to the documentation.
In terms of my knowledge level, I know floating point numbers are represented as bitstrings with a sign bit, exponent bits, and mantissa bits, but don’t really know much else.
Thanks in advance!
How NaN are handled is outlined in IEEE-754. All comparisons between NaN and any number including itself return false.
=== on the other hand is a different operation that checks that no operation could tell them apart. For mutable structs this is pointer equality and for immutable structs this is bitwise equality.
There are actually several different representations for NaN’s, which are not
===. The best way to check if a value is NaN is with the function
Thanks for pointing me to IEEE-754. I’ve always thought of
== as checking for equality of value, and did not know there was a specification given by IEEE. Now it makes sense that
NaN==NaN is false but
Nan === Nan.
Do you also happen to know why
isequal was designed to return
true for two
NaN in Julia?
NaNs not being equal to each other can often be unhelpful behavior. For those cases
isequal is simpler then having to explicitly handle NaN’s.
=== isn’t much help for those cases as there can be multiple different bitwise representations of NaNs.
@WschW notes, there is only one best practice when it comes to determining if one or more values is “not a number” (NaN): use
isnan(x) or, to determine if two values are NaNs, use e.g.
nans(x,y) = isnan(x) && isnan(y) . And, fortunately,
isnan(x) runs fast.
isequal is used in hashing, so it has to work like this. See
07:15PM - 12 Jun 18 UTC
05:34PM - 30 Apr 20 UTC
One plausible and tempting upshot of the conversation at https://discourse.julialang.org/t/possible-bug-in-unique-set/5371 is that it might make sense for Julia to sort and...
for a related discussion.
isequal is defined differently then
===. you can see the definition for how the former handles floats is:
isequal(x::AbstractFloat, y::AbstractFloat) = (isnan(x) & isnan(y)) | signequal(x, y) & (x == y)
This function returns true if both values are NaN’s.
This is distinct behaviour from
=== which in this case would return false if either the sign or any part of the mantissa differed.
Ah that makes sense. Did not know
isequal was the function used for hashing. Thanks!
Thank you all for clarifying the differences as well as why they exist!