Isn’t this an inconsistency of NaN?
It appears that these are two different bit values although they both print as
julia> reinterpret(UInt,0/0) 0xfff8000000000000 julia> reinterpret(UInt,NaN) 0x7ff8000000000000 julia> 0/0 == NaN false
they differ only by a single bit, presumably the sign bit
julia> 0.0 == -0.0
julia> 0.0 === -0.0
so at least
julia> (0/0)*false == NaN*false true
That’s correct, they can’t be egal (
===) because the sign bit is different:
julia> reinterpret(UInt, 0.0) 0x0000000000000000 julia> reinterpret(UInt, -0.0) 0x8000000000000000
julia> bitstring(0.0) "0000000000000000000000000000000000000000000000000000000000000000" julia> bitstring(-0.0) "1000000000000000000000000000000000000000000000000000000000000000"
Ok, and what about:
In IEEE-754, the IEEE standard for floating point arithmetic, which Julia and most other languages use,
NaNs are encoded with the exponent field filled with ones. According to the standard, the sign bit does not matter for determining
NaNness, and the sign bit is precisely what’s different between
NaN. I’m not sure exactly why
0/0 results in a different sign bit, but it could well just be an implementation detail. Next, there’s the multiplication with the
false, which (eventually) hits this method:
copysign is what causes the sign bit of the
NaN to appear in the final result. I’m not sure whether that’s intended. I suppose it is a little weird that information that’s supposed to be (mostly) immaterial has an observable effect here. Then again, it seems harmless.
Why is why the way to determine
NaNness is to use
isnan and not any number of consecutive
='s. You’re not supposed to do
0/0 == NaN to check if the lhs is
julia> haskey(Dict(NaN => nothing), 0/0) true
There are several things to unpack in this post.
false*NaNis special cased to make
false“strong”, see the implementation
NaNs is a bit misleading, as
NaNs are not supposed to have a sign:
julia> sign(0/0) NaN julia> copysign(1.0, 0/0) -1.0
I don’t know the arcane details of IEEE 754 about whether this is the intended behavior. In any case, it is mostly innocuous.
(NaN*(0/0))*falseis the same phenomenon, except the sign bit comes from the first operand.
It’s what the hardware does, iirc.
isequal (which is what
isequal(NaN, 0/0) == true.
Whoa there. I don’t know if these are officially bugs but they are at odds with the IEEE 754 spec, which reads in part:
For an operation with quiet NaN inputs, other than maximum and minimum operations, if a floating-point result is to be delivered the result shall be a quiet NaN which should be one of the input NaNs.
I understand why people usually want false*x to be falsy but NaN is falsy enough and more correct than 0.0 for false*NaN.
I agree. But since this has been in the language for a while, I think a lot of programmers (myself included) use
false*x on uninitialized data and expect to get rid of
NaNs that way.
I think it would be nice if Julia had a “strong zero” in a type of its own. I even wrote a package implementing that a while back (though I never registered it or upgraded it to be 1.0 compatible.)
I think the argument is that IEEE-754 does not pertain to operations involving boolean inputs. I’m not picking sides on whether or not the current behavior of various operations with mixed floating point number and boolean inputs is ‘right’, but it’s not a clear-cut case.