Live data from Hacker News

Demystifying NaN for the Working Programmer

lucidchart.com

11–20 of 38 posts

Re: Demystifying NaN for the Working Programmer

#11
post #4

Imagine doing if(x) ..., where x can be NaN. Shouldn't that throw an exception in most cases? Why are our compilers not doing it that way?

The compiler presumably can't know in most cases, but the runtime might be able to throw. It depends on the language implementation and the tradeoffs.

Re: Demystifying NaN for the Working Programmer

#12
post #8

Earlier quoted context omitted.

Signaling NaNs raise exceptions in some operations. Is comparison one of these?

They “raise exceptions” in the IEEE 754 sense, which is not at all the same thing as what most programming languages mean by “raise exception”. It means that they set a sticky flag in a register that may be queried at a later point, not that program control flow is redirected.

The only use I saw for this is that you can enable compiler flags to crash the program when NaNs are encountered. Useful for testing Fortran code, in my experience. I didn’t see any support for other languages I’ve used.

Re: Demystifying NaN for the Working Programmer

#13

I did a code assignment for a potential JavaScript heavy job in 2014, for some reason I think isNaN was part of the language then because I have a memory deciding not to use it (but could be misremembering), at any rate I did Number(x) !== Number(x) at some point. In the meeting when they went over the code the guy who did it said we were wondering why you did this? So I had to explain NaN to him. He really did not k…

Related: I’ve met developers who think NaNs are a language or library (notably pandas) feature.

Re: Demystifying NaN for the Working Programmer

#14
post #10
post #4

Imagine doing if(x) ..., where x can be NaN. Shouldn't that throw an exception in most cases? Why are our compilers not doing it that way?

Should it? It isn't obvious to me at all that throwing an exception in this case is the best behaviour. Throwing an exception when testing a value for 'truthiness' is extremely surprising. On the other hand, I would strongly discourage 'if(x)' where x is a float that may be NaN purely because the 'correct' behaviour here isn't clear to me.

How about the case where x is (y > 0)? If y is NaN, shouldn't x be boolean-NaN? And shouldn't if(x) throw an exception? Or shouldn't (y > 0) throw an exception if you don't want boolean-NaNs?

Re: Demystifying NaN for the Working Programmer

#15
post #12

Earlier quoted context omitted.

They “raise exceptions” in the IEEE 754 sense, which is not at all the same thing as what most programming languages mean by “raise exception”. It means that they set a sticky flag in a register that may be queried at a later point, not that program control flow is redirected.

The only use I saw for this is that you can enable compiler flags to crash the program when NaNs are encountered. Useful for testing Fortran code, in my experience. I didn’t see any support for other languages I’ve used.

C lets you set and query the flag state with the `` functions in theory, but compiler support for rigorously adhering to IEEE 754 semantics around these operations is pretty limited in most compilers, to say the least. Clang has been making some progress on support recently.

Re: Demystifying NaN for the Working Programmer

#16
NaN is a cancer. The choice that NaN == Nan being false is just wrong. Every type, every variable can have multiple reason for being invalid. Yet, no other type has ever chosen to make invalid values not being equal to themselves.

Pointers can be invalid. They can be invalid for any number of reason. Lack of memory, object not found, etc. No one ever suggest that null should not equal null.

File handle can be invalid. They can be invalid for any number of reasons: file not found, access denied, file server is offline. No one has ever made invalid handles not being equal to themselves.

The justification for NaN not being equal to themselves is just bonk.

Re: Demystifying NaN for the Working Programmer

#17
post #14
post #10

Earlier quoted context omitted.

Should it? It isn't obvious to me at all that throwing an exception in this case is the best behaviour. Throwing an exception when testing a value for 'truthiness' is extremely surprising. On the other hand, I would strongly discourage 'if(x)' where x is a float that may be NaN purely because the 'correct' behaviour here isn't clear to me.

How about the case where x is (y > 0)? If y is NaN, shouldn't x be boolean-NaN? And shouldn't if(x) throw an exception? Or shouldn't (y > 0) throw an exception if you don't want boolean-NaNs?

That's easy: y > 0 is False, not NaN.

You may not think this is wise, but this is very much how comparisons with NaN are defined.

And I think this is better than exception raising. Again, I think it would be _really_ weird for simple value comparisons to throw.

Re: Demystifying NaN for the Working Programmer

#18

NaN is a cancer. The choice that NaN == Nan being false is just wrong . Every type, every variable can have multiple reason for being invalid. Yet, no other type has ever chosen to make invalid values not being equal to themselves. Pointers can be invalid. They can be invalid for any number of reason. Lack of memory, object not found, etc. No one ever suggest that null should not equal null. File handle can be invali…

In a world without generic programming, NaN not being equal to itself makes a certain amount of sense for some kinds of numeric code. But in a world with reusable generic algorithms the calculation changes -- here equality/ordering relations really must be transitive or weird shit happens. In C++ it's undefined behavior to call `std::sort` or `std::unique` on list of floats containing NaN.

Most languages nowadays have standard-library functions/types that require well-behaved equality, so why have a builtin type for which equality is not well-behaved?

Re: Demystifying NaN for the Working Programmer

#19
This article conflates the representational limits of floating point with the concept of NaN in a way that I suspect will lead to more confusion, not less.

Zero/zero doesn’t return NaN because it isn’t representable within floating point - it returns NaN because it is an expression that has no mathematical meaning.

The fact that sqrt(-1) has two valid nonreal answers has nothing to do with why it returns NaN - after all, sqrt(4) has two valid real answers so is also technically not representable by a single floating point value, but that doesn’t typically result in NaN.

NaN is just an error value you get when you ask floating point math a dumb question it can’t usefully answer.

Far more interesting and subtle are the ways in which positive and negative infinity and positive and negative zero let you actually still obtain useful (at least for purposes of things like comparison) results to certain calculations even if they overflow the representable range.

Re: Demystifying NaN for the Working Programmer

#20
post #17
post #14

Earlier quoted context omitted.

How about the case where x is (y > 0)? If y is NaN, shouldn't x be boolean-NaN? And shouldn't if(x) throw an exception? Or shouldn't (y > 0) throw an exception if you don't want boolean-NaNs?

That's easy: y > 0 is False, not NaN. You may not think this is wise, but this is very much how comparisons with NaN are defined. And I think this is better than exception raising. Again, I think it would be _really_ weird for simple value comparisons to throw.

> Again, I think it would be _really_ weird for simple value comparisons to throw.

But ... why?

You may say that NaN > 0 is defined as False, but we know that's not how programmers think, most of the time.

In code like if(y > 0) steer_car_to_left() I don't want the compiler or the IEEE standard to make any choices for me! Let it throw, so emergency systems can kick in.

Post reply on HN