Faster `min`,`max` for `Float64|32`

In fact negNaN (or -NaN) has been used in the test system. We’d better not drop that.
At present, if the two inputs are NaNs with different signs:

  • Base.min always returns the one with positive sign
  • Base.max always returns the one with negetive sign
  • Base.minmax(x, y) always returns (x, x)

I just wonder which style is better?

If min and max also return the first of two NaNs (no matter their signs), I think the following code could handle -NaN and Float16 better:

FastFloat = Union{Float32, Float64}
_isless(x::T, y::T) where {T<:AbstractFloat} = (x < y) || (signbit(x) > signbit(y))
min(x::T, y::T) where {T<:AbstractFloat} = isnan(x) || ~isnan(y) && _isless(x, y) ? x : y
max(x::T, y::T) where {T<:AbstractFloat} = isnan(x) || ~isnan(y) && _isless(y, x) ? x : y
minmax(x::T, y::T) where {T<:AbstractFloat} = min(x, y), max(x, y)

_isless(x::T, y::T) where {T<:FastFloat} = signbit(x - y)
min(x::T, y::T) where {T<:FastFloat} = ifelse(isnan(x) | ~isnan(y) & _isless(x, y), x, y)
max(x::T, y::T) where {T<:FastFloat} = ifelse(isnan(x) | ~isnan(y) & _isless(y, x), x, y)

_isless(x::Float16, y::Float16) = _isless(widen(x), widen(y))