6 ms·
Hey, that’s my answer! /wave Strangely, I was just adding some more material to this answer as I’ve never really been completely satisfied with it; then I fli
by stephencanon 12y ago
Hey, that’s my answer! /wave
Strangely, I was just adding some more material to this answer as I’ve never really been completely satisfied with it; then I flip over to hacker news and there it is. Anyway, if anyone has other IEEE-754 questions, I’ll try to answer.
- haberman 12y agoWow, I never would have guessed that a significant reason was historical, so that x != x could provide a robust way to detect NaN without requiring a special API. Is there a similar test for infinity?
- jules 12y agoThat reasoning is incorrect. If they had chosen NaN == NaN, then the test for NaN could be simply x == NaN... The other reason mentioned is also unconvincing. Surely preserving the law x==x is more important than the law x==y <=> x-y==0. Then we have: > Regarding your comment "that doesn't mean that the correct answer is false", this is wrong. The predicate (y < x) asks whether y is less than x. If y is NaN, then it is not less than any floating-point value x, so the answer is necessarily false. Clearly this reasoning is incorrect for the simple reason that the same reasoning can lead to the opposite conclusion. If y is NaN then we can't say that y < x is definitely true but neither can we say that y < x is definitely false. Here is my argument for why NaN == NaN should be true. The == operator for floats should rarely be used. If you want to know whether two floats can be considered the same, then you should always use some other condition like |x-y| < epsilon, and NOT x == y. The reason is that floating point arithmetic is inexact, so even a slight roundoff error will make x == y false. So if its job is not to test whether two floats are the same numerically then what is the job for the == operator? Its job is to test whether x and y are precisely the same float. The x == y operator should not pretend to work on the abstraction that x and y are kinda-sorta real numbers, because such an operator is useless anyway because the criterion for that needs to be application specific. It should compare floats while admitting that we are comparing floats which can take on the value +infinity -infinity +0 -0 and NaN, and we are not comparing real numbers which do not have those values. That's why NaN == NaN should be true.
- stephencanon 12y ago> If they had chosen NaN == NaN, then the test for NaN could be simply x == NaN Not in languages that didn’t have a name for NaN it wouldn’t. > you should always use some other condition like |x-y| < epsilon, and NOT x == y. This is a popular myth, but it is false. There are circumstances in which exact equality comparisons in floating-point are perfectly appropriate. > Its job is to test whether x and y are precisely the same float. No; if it were we would have +0 != -0. You’re looking for totalOrder(x,y) or a related predicate.
- jules 12y ago> Not in languages that didn’t have a name for NaN it wouldn’t. ...then use NaN = 0/0. > This is a popular myth, but it is false. There are circumstances in which exact equality comparisons in floating-point are perfectly appropriate. Can you give an example where == is appropriate, but where you want NaN == NaN to be false? > No; if it were we would have +0 != -0. You’re looking for totalOrder(x,y) or a related predicate. Exactly, +0 == -0 should be false too. totalOrder(x,y) is what == should have been (or at least the equality part of it). p.s. An arguably more serious issue with IEEE floats is rounding modes. The round up/round down modes are tantalizingly close to providing the ability to do ironclad approximate real arithmetic in the sense that you could give upper/lower bounds on the exact value. The problem is that the rounding modes only involve giving an upper/lower bound on the output given an exact input, rather than an upper/lower bound on the output given an upper/lower bound on the input. So it's not compositional which means you can't guarantee anything.
- thedufer 12y ago> ...then use NaN = 0/0. Many languages throw an error when you divide by zero. As far as I can tell, if x != x didn't work you would have to resort to bizarre contortions like `x == float("NaN")` for such tests in Python (the problems: there are no NaN or Infinity constants and division by 0 throws). Also, since you expect == to do bit equality on floats, you will be distinguishing between the huge number of representation of NaN, so NaN = 0/0 isn't valid even if there is a NaN constant (and which one would it be?).
- MaxGabriel 12y agoWhat about it made you not completely satisfied?
- stephencanon 12y agoIt was focused on “how do we approach this sort of decision today” and neglected some of the historical context that informed the decision making. It’s important to consider that the rules for NaN we essentially inherited wholesale from the 8087, which was the proving ground for many of the ideas in IEEE-754.
- benjamincburns 12y agoHa, thanks for chiming in, and for answering that question. It's interactions like this that keep me stupid excited about the internet, and hopeful that someday the ubiquitous, nebulous "they" (as in "they say...") will die.