If NaNs were meant to represent unknown quantities, then they would return false for all comparisons. But NaN != NaN is true. Assuming that two unknowns are always different is just as incorrect as assuming that they're always the same.
I'd also push back on the idea that this behavior makes sense. In my experience it's a consistent source of confusion for anyone learning to program. It's one of the clearest violations of the principle of least astonishment in programming language design.
As others have noted, it makes conscientious languages like Rust do all sorts of gymnastics to accommodate. It's a weird edge case, and imo a design mistake. "Special cases aren't special enough to break the rules."
Also, I think high level languages should avoid exposing programmers to NaN whenever possible. Python gets this right: 0/0 should be an error, not a NaN.
`NaN == NaN` vs `NaN != NaN` forces us to pick which idea to violate:
1. A value of a given type, either a literal or a value in memory, should represent a single concrete value, semantically (`5` represents the number five).
2. Classical logic (if A = B is true, then A != B is false).
I vote for violating #1, because we control those terms better. Is it weird that we invented a value that represents "unrepresentable" (as opposed to representing "no value")? Yes, but there are practical reasons for why we did it. It would be much more weird/surprising to violate classical logic.
As a standard for floating point representation and computation, IEEE 754 solved multiple long-standing serious problems better than anything that came before it. I don't think its sensible to judge it with a PL design lens like "principle of least astonishment"; certainly not as if IEEE754 is a peer to Rust or Python. Or, you could learn about the surprise, frustration, and expense involved in trying to write portable numeric code in the 1970s, prior to IEEE 754:
I like this justifiation of NaN != NaN; it emphasizes that NaN has representional intent, more than just some bit pattern.
We take for granted that (except for things like x86 extended precision registers) floating point basically works the same everywhere, which was the huge victory of IEEE 754. It easy to lose sight of that huge win, and to be ungrateful, when one's first introduction to IEEE 754 are details like NaN!=NaN.
1/0 is an error (SIGFPE). log(-5) is a value (NaN).
---
I suppose you could have this "no reflexive equality" sentinel, but it applied so randomly in languages as to be eternally violate the principle of least astonishment.
Python is extra annoying though with refusing to support division through zero the way other programming languages with IEEE floats do (i.e. output inf or nan instead of throwing an exception), even though it has no problem doing things like float('inf') / float('inf') --> nan. It specifically does it for division through zero as if it wants to be a junior grade calculator just for this one thing. They could at least have fixed this when breaking backwards incompatibility from python2 to 3...
In most languages, `x: float = 0` involves an implicit conversion from int to float. In Python, type annotations have no impact on runtime behavior, so even though the type checker accepts this code, `type(x)` will be `int` -- python acts as if `int` was a subtype of `float`.
It would be weird if the behavior of `1 / x` was different depending on whether `0` or `0.0` was passed to a `x: float` parameter -- if `int` is a subtype of `float`, then any operation allowed on `float` (e.g. division) should have the same behavior on both types.
This means Python had to choose at least one:
1. division violates the liskov substitution principle
2. division by zero involving only integer inputs returns NaN
3. division by zero involving only float inputs throws
exception
4. It's a type error to pass an int where a float is expected.
They went with option 3, and I think I agree that this is the least harmful/surprising choice. Proper statically typed languages don't have to make this unfortunate tradeoff.
C does different things for 0.0 / 0.0 and 0 / 0 and it's not that weird to deal with (well it has other issues like it being platform dependent what happens with this). JS has no problem with it either (0.0 / 0.0 gives nan, 0n / 0n gives exception since it are integers).
Python is the only language doing this (of the ones I use at least).
I don't think the notation `x: float = 0` existed when it was new by the way so that can't be the design reason?
since python seems to handle integer through integer divisions as float (e.g. 5 / 2 outputs 2.5), 0 / 0 giving nan would seem to be expected there
> liskov substitution principle
that would imply one is a subtype of another, is that really the case here? there are floats that can't be represented as an integer (e.g. 0.5) and integers that can't be represented as a double precision float (e.g. 18446744073709551615)
Python chose, quite some time ago, not to follow C's lead on division:
PEP 238 – Changing the Division Operator (2001) [1]
The rationale is basically that newcomers to Python should see the results that they would expect from grade school mathematics, not the results that an experienced programmer would expect from knowing C. While the PEP above doesn't touch on division by zero, it does point toward the objective being a cohesive, layman-friendly numeric system.
C and JavaScript both treat integers and floats as separate types. In Python, ints and floats with the same numeric value are considered identical for almost all purposes.
Nah. Python gets it right; all high level languages should operate this way. Division by zero is a bug 90% of the time. Errors should never pass silently. Special cases aren't special enough to break the rules.
IEEE floats should be a base on which more reasonable math semantics are built. Saying that Python should return NaN or inf instead of throwing an error is like saying that Python should return a random value from memory or segfault when reading an out-of-bounds list index.
Exactly. Programming language design should be coherent and consistent, not just for floats, but arrays, classes, pointers, or anything else that it offers.
And the sensible thing will depend on that language.
There's no non-confusing option for comparisons. You have two invalid values, but they aren't necessarily the same invalid value. There are multiple operations that can produce NaN.
It's a sentinel value for an error. Once you have an error, doing math with the error code isn't sensible.
There are no non-confusing options, but some of those are still clearly worse than others.
What should sorted([3, nan, 2, 4, 1]) give you in Python?
A) [1, 2, 3, 4, nan] is an good option
B) [nan, 1, 2, 3, 4] is an good option
C) An error is an good option
D) [3, nan, 1, 2, 4] is a silly, bad option. It's definitely not what you want, and it's quiet enough to slip by unnoticed. This is what you get when Nan != NaN
NaN == NaN is wrong. NaN != NaN is wrong, unintuitive, and breaks the rest of your code. If you want to signal that an operation is invalid, then throw an error. The silently nonsensical semantics of NaN are the worst possible response
Markets being completely free got us in this mess, and while sound on paper has so many potential ways to go wrong it should be controlled by the working class either directly or indirectly through voting
Theft is a symptom, not a disease. Eliminate the disease and theft effectively disappears
Educational choice deserves to be respected so long as it isn't being used to propagate objectively false information
> Markets being completely free got us in this mess, and while sound on paper has so many potential ways to go wrong it should be controlled by the working class either directly or indirectly through voting
Is that what got us into this mess? (Which mess?) Take medical care, for instance. Is that a free market? Not really, no.
I mean, there are clearly markets that can be too free. No, you can't put poison in food and call it "free market". You can't roll through the farmer's market with guns and take everybody's stuff and call it "free market". There is a level of regulation where markets work best, and they work worse with either too much or too little regulation.
But something like the medical market... most people can't shop around for insurance; their employer works with only one insurer. Most people can't shop around freely for doctors; they have to go to someone within their plan. And so on. That's not even close to a free market.
> Theft is a symptom, not a disease. Eliminate the disease and theft effectively disappears
Great. Now tell us what you think the disease is, and how you think we should eliminate it.
> Educational choice deserves to be respected so long as it isn't being used to propagate objectively false information
And who is going to authoritatively determine what is objectively false? You just appointed that person dictator of the educational system. (See previous remarks about free markets.)
The disease is poverty most of the time, if not directly then indirectly. Solving it is wealth redistribution at a massive scale but unfortunately our masters need another yacht
The educational system was working pretty well in terms of objectivity until the right wing started screaming about kids pissing in litter boxes and universities censoring right wing ideology.
The reality is that right wing ideology is unpopular when exposed to objective discussion. Turns out most people dont agree those concepts.
So now we have an administration who's actively working to censor universities to compel speech and censor ideas it doesnt like via lawsuits, executive orders, and funding elimination.
Neither of these is right wing value. They are right wing talking points right uses when it suits them and completely ignores when it does not suit them.
>Criminal offenses are punishable by incarceration.
And what happens if you don't pay civil (or criminal) fines? A bench warrant gets issued and you get arrested. And if you get a contempt charge in all this guess where you can go?
The only "real difference" between a criminal offense where they "can" jail you but usually just fine you is procedural.
I would rather catch a bullshit DUI than have a local building commissioner coming after me for some violation. They're both $10k problems, but with one of them you have "real rights"
>Unauthorized immigration to the US is NOT punishable by incarceration.
The problem wasn't what the statutory punishment is or isn't.
The problem was the unilateral nature of it. Hence all the hoopla over warrant types, sloppy behavior, etc.
This is an incomplete sentence:
> All cases where you are in a CPU intensive blocking task that, if you’re not careful, could starve all the others.
reply