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

Inconsistency in max(-Inf,NaN) #10729

Closed
timholy opened this issue Apr 3, 2015 · 11 comments
Closed

Inconsistency in max(-Inf,NaN) #10729

timholy opened this issue Apr 3, 2015 · 11 comments

Comments

@timholy
Copy link
Member

timholy commented Apr 3, 2015

No description provided.

@timholy
Copy link
Member Author

timholy commented Apr 3, 2015

On 0.3 we have

julia> min(-Inf,NaN), min(Inf,NaN), max(-Inf,NaN), max(Inf,NaN)
(-Inf,Inf,-Inf,Inf) 

but on 0.4 we currently have

julia> min(-Inf,NaN), min(Inf,NaN), max(-Inf,NaN), max(Inf,NaN)
(-Inf,Inf,NaN,Inf)

Aside from the fact that this turns out to break Winston, this seems inconsistent. Last touched in #9416 (7d2e697), CC @lbenet.

No matter how this gets fixed, we should add a test for this behavior.

@timholy
Copy link
Member Author

timholy commented Apr 3, 2015

We should also test both orders of the arguments, since the implementation is not symmetric in its arguments.

@tkelman
Copy link
Contributor

tkelman commented Apr 3, 2015

related - #7866

lbenet pushed a commit to lbenet/julia that referenced this issue Apr 3, 2015
StefanKarpinski added a commit that referenced this issue Apr 8, 2015
Solves the inconsistency #10729 and add tests
@JeffBezanson
Copy link
Member

closed by #10736

@stevengj
Copy link
Member

This still seems wrong. It seems like min(-Inf,NaN), min(Inf,NaN), max(-Inf,NaN), max(Inf,NaN) should give (-Inf, NaN, NaN, Inf).

@eschnett
Copy link
Contributor

If you argue that max(Inf,NaN) == Inf, then you can also argue that 1.0 * NaN == NaN.

LLVM recently had a very long discussion about what "undefined" means. The upshot is that there are two different meanings: "I don't know what value" and "there is no possible value", corresponding to the types Any and None (Union()). If you say that a NaN represents any value (you just don't know which), then you want to preserve identities such as max(Inf,...)==Inf and 1.0*x==x. But if you say that a NaN represents no value at all, then max(...,NaN)==NaN and ...*NaN==NaN.

Given that NaN is the result of e.g. log(-1.0), it seems that floating point arithmetic uses the latter idea: a NaN is a new kind of number to ensure all functions are complete (not partial). This then breaks identities, and NaNs become infectious.

@jiahao
Copy link
Member

jiahao commented Aug 11, 2015

Unfortunately IEEE 754-2008 is not consistent about NaN being "I don't know which floating point value" and "there is no possible floating point value". In this case, the standard wants the former; it defines minNum and maxNum functions as follows:

screen shot 2015-08-11 at 11 08 06 am

In particular, the standard defines minNum and maxNum to drop NaNs, which is exactly how min and max behave.

julia> min(-Inf,NaN), min(Inf,NaN), max(-Inf,NaN), max(Inf,NaN)
(-Inf,Inf,-Inf,Inf)

@jiahao
Copy link
Member

jiahao commented Aug 11, 2015

I'm also reminded that this exact discussion was brought up in #7866, and in particular @ArchRobison got a response from William Kahan himself in #7866 (comment) suggesting that min and max don't necessary have to be in 1-1 correspondence with the IEEE 754-2008 functions minNum and maxNum.

@lbenet
Copy link
Contributor

lbenet commented Aug 11, 2015

@stevengj I don't understand why min(-Inf,NaN) === -Inf but min(Inf,NaN) === NaN ? I thought that the issue in #12552 is to poison the result with NaNs.

One more thing: there is -NaN (which is displayed as NaN); then, what do you expect for minmax(-NaN,NaN)? Currently we get

julia> minmax(NaN,-NaN) === (-NaN,-NaN)
true

julia> minmax(-NaN,NaN) === (NaN,NaN)
true

@stevengj
Copy link
Member

@ibanet, see the explanation by Kahan in #7866.

@lbenet
Copy link
Contributor

lbenet commented Aug 11, 2015

@stevengj Thanks, I now understand the reason for the expected results.

Yet, currently, there are functions with the property pointed out by Kahan which do not yield f(x,NaN) -> f(X,y) (independently of y) but are poisoned by NaNs. As an example, f(x,y) = (3-x)*y + 2 satisfies that for X=3 it is independent of y, since f(X,y)=2, but f(3,NaN) yields a NaN instead of 2. The same is obtained for f(Inf,NaN).

Once said this, I agree for poisoning min, max and minmax with NaNs, except for the Inf and -Inf. But, again, what do we want for min(NaN,-Nan)? Do we care about the sign?

I think it is important to preserve commutativity, and probably also introduce minnum, maxnum (or whatever name it is decided) which follow the standard; see this comment by Arch Robinson.

EDIT: Corrected the link to point to the comment.

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

7 participants