3 ms·
> 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 alw
by 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?).
- jules 12y agoStill not a valid complaint. You want to test for NaN because some computation might result in NaN. Ergo, there is some expression in your language to produce NaN. Use that expression to define NaN. Response to edit: There can be several answers to this question. If you're gonna be stuck with the IEEE floats, obviously the right thing to do is an isNaN predicate, but arguably there shouldn't be more than 1 NaN in the first place.
- derefr 12y agoX/0.0 is safe, and will always return NaN, no matter the language -- as long as 0.0 is a representation of an IEEE754 floating-point value, and as long as the expression "X/0.0" is interpreted as coercing X into a floating-point value in order to do fpdiv(X, 0.0) -- then safely returning Infinity here (or NaN in the case of 0/0.0) is required of the FPU in order for it to be considered IEEE754-compliant. On the other hand, X/0 (integer division-by-zero, where X is not a floating-point value either) usually does cause an exception. In fact, in bare-metal ASM without a trap-handler interrupt set up, it halts the processor entirely.
- mansr 12y ago> On the other hand, X/0 (integer division-by-zero, where X is not a floating-point value either) usually does cause an exception. That's true for x86, but not for most other architectures.
- stephencanon 12y ago> use NaN = 0/0. You may not be able to do that it traps are enabled for the invalid exception. (The NaN may be coming in from a data file | over the wire | from another process prepared under an entirely separate floating-point environment that didn’t have traps enabled). > Can you give an example where == is appropriate, but where you want NaN == NaN to be false? I’ll give you one where == is appropriate but where you want -0 == +0: if (x == 0) return someFormulaValidAtZero(x); else return somethingEasierToComputeWithAnImplicitFactorOfx(x)/x; this is actually a fairly common idiom. Here’s my standard question for the “NaN should equal NaN" crowd, to which I’ve never seen a satisfactory response: If NaN == NaN, how should NaN compare against zero? I think we all agree that NaN != 0. If NaN < 0 or NaN > 0, you’re giving up x > y ==> -x < -y, which to my mind is a bigger loss than trichotomy. If NaN ?? 0, then trichotomy goes out the window, and presumably NaN ?? (any number), at which point NaN is unordered with respect to every number, but somehow equal to itself, which is also pretty darn weird. You give something up any way you tackle this. You may reasonably argue that one of these options is less bad than another, but you can’t pretend that there’s a canonical right approach (though nearly every algebraist I’ve ever met believes that you should be able to until they really dig into it; analysts are much more realistic). w.r.t. rounding modes, I partially agree. Had I been on the committee in 1985, I would have argued against formalizing round up and round down (round to zero is quite useful for some signal-processing applications). It’s a mistake to look at them and say “they aren’t interval arithmetic so they’re useless”, however. They were never intended to be interval arithmetic; rather they were intended to be building-blocks for interval arithmetic systems. (My problems with them are that (a) they’re global rather than operation-by-operation—this was corrected in the 2008 IEEE-754 document and (b) round-up and round-down are no more useful building blocks than round-to-zero (which we already have) and round-away-from-zero, which would free up space for another useful rounding mode (either round-ties-away “schoolbook rounding”) or round-to-odd, which is extremely useful for library implementors).
- jules 12y ago> (The NaN may be coming in from a data file | over the wire | from another process prepared under an entirely separate floating-point environment that didn’t have traps enabled). ........................................if NaN is incoming from a data file, then tadaaaa there's your way to make a NaN to compare to. I can't believe we're still playing that game. > I’ll give you one where == is appropriate but where you want -0 == +0: And how would that example work for x very close to 0? Even in that example, you'd want |x|<eps. But anyway, I'm not even sure that having 2 zeros is a great idea either. > If NaN == NaN, how should NaN compare against zero? It shouldn't. < is an operation that works on the abstraction that floats are kinda-sorta real numbers, and NaN isn't so NaN < x should be an error.