Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nextfloat behaviour near Inf #16206

Closed
DNF2 opened this issue May 5, 2016 · 7 comments
Closed

nextfloat behaviour near Inf #16206

DNF2 opened this issue May 5, 2016 · 7 comments

Comments

@DNF2
Copy link

DNF2 commented May 5, 2016

I find this behaviour surprising:

>> nextfloat(Inf)
Inf
>> nextfloat(Inf, 2)
Inf
>> nextfloat(prevfloat(Inf))
Inf
>> nextfloat(prevfloat(Inf), 2)
NaN

I would expect the last call to return Inf as well.

The following code seems to do what I expected:

function nextfloat(x::Float64, i::Integer)
    if i == 0 || (isinf(x) && sign(x) == sign(i))
        return x
    end
    xint = float_lex_order(reinterpret(Int64,x), i)
    intmax = reinterpret(Int64, Inf64)
    int0 = reinterpret(Int64, -0.0)
    intmin = reinterpret(Int64, -Inf64)
    return (0 <= xint <= intmax || int0 <= xint <= intmin) ?
        reinterpret(Float64, xint) : flipsign(Inf, x)
end
@simonbyrne
Copy link
Contributor

This is clearly an error. Even more worrying is:

julia> nextfloat(prevfloat(Inf),typemax(Int))
-2.2250738585072024e-308

@cyberbryce
Copy link
Sponsor

The manual states that nextfloat and prevfloat use lexicographic order, but to me this meant that NaN's would either be ordered by their bits, or not ordered at all. The previous routine appears to give you the next 'higher' NaN in the sense of bits. The proposed routine instead follows the second branch of the final conditional and returns a signed infinity:
Previous behavior:

julia> bits(NaN)
"0111111111111000000000000000000000000000000000000000000000000000"
julia> nextfloat(NaN,1)
NaN
julia> nextfloat(NaN,1)===NaN
false
julia> bits(nextfloat(NaN,1))
"0111111111111000000000000000000000000000000000000000000000000001"

Proposed behavior:

julia> nextfloat(NaN,1)
Inf
julia> bits(nextfloat(NaN,1))
"0111111111110000000000000000000000000000000000000000000000000000"

@cyberbryce
Copy link
Sponsor

Apologies -- Contrary to what I said, Simonbyrne's actual commit (rather than the proposed code above) treats all NaNs the same.

@simonbyrne
Copy link
Contributor

simonbyrne commented May 6, 2016

Seems like the manual isn't quite right, since

julia> nextfloat(-0.0)
5.0e-324

julia> lexless(-0.0, 0.0)
true

nextfloat and prevfloat are supposed to correspond to the nextUp and nextDown functions in the IEEE754-2008 spec, which states:

sourceFormat nextUp(source)
sourceFormat nextDown(source)
nextUp(x) is the least floating-point number in the format of x that compares greater than x. If x is the negative number of least magnitude in x’s format, nextUp(x) is −0. nextUp(±0) is the positive number of least magnitude in x’s format. nextUp(+∞) is +∞, and nextUp(−∞) is the finite negative number largest in magnitude. When x is NaN, then the result is according to 6.2. nextUp(x) is quiet except for sNaNs.
The preferred exponent is the least possible.
nextDown(x) is −nextUp(−x).

I'm not really sure which part of 6.2 they're referring to, but there is there is this sentence:

6.2.3 NaN propagation
An operation that propagates a NaN operand to its result and has a single NaN as an input should produce a NaN with the payload of the input NaN if representable in the destination format.

which would seem to indicate that for NaNs we should return the same payload.

@cyberbryce
Copy link
Sponsor

That makes sense. Thanks for fixing this. FYI: I found that when I static typed the arguments, the new routine introduces about six additional branches, which we might want to worry about. However, nonetheless, it is slightly more performant than the previous version.

@simonbyrne
Copy link
Contributor

simonbyrne commented May 7, 2016 via email

@nalimilan
Copy link
Member

By the way, the two-argument form of nextfloat isn't documented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants