Whenever I write something about math, I am afraid of being knocked out with a metal bar by a real mathematician, but here we go, confronting our fears:
"Why does NaN exist at all, rather than resulting in an exception or error?"
Because it is neither an exception nor an error. It is a perfectly valid result for a calculation. You have several use cases in mathematics where you are receiving the equivalent to "NaN", i.e., something that cannot be measured. Think the calculation of an intersection between two parallel lines. Or the calculation of the mass of a photon.
In these cases, where you are going for "the math side of life" in your code (I can imagine this applies mainly to scientific software), we have the following situation:
- They are no errors, the variables have the values that they need to have, the calculations have been done, and this is the result. Sadly, not a real number (A complex one maybe? Maybe an indetermination that can be solved using other mathematical methods?), still you have the answer to the calculation.
- They are no exceptions, nothing is wrong with your code, this is not an anomalous condition, this is the answer: "NaN" (where you expecting 42?). No need to stop the flow of your program here: inform the user that the calculation has no solution or it is a non-determined one, and let him be happy with it (note: I lie a bit, read the latest paragraph).
You want the program to crash and die then and there so that you can
easily find where it went wrong.
You are totally right: you may still handle it as an exception or as an error if the concept of NaN is not a valid result in the context of your program .Imagine calculating the necessary diameter of a column for a football stadium and getting NaN. Ugh... that would be for sure an error, I want to build that stadium, give me a diameter!. You are also totally wrong: please, don´t tell you will find "easily" where it went wrong just because you trigger an exception after NaN. I knew some people debugging meteorological models that would like to have a word with you (these equations are not fun).
You have nowadays many libraries and implementations that take opinionated decisions about what are errors, what are exceptions, etc. The IEEE designers left the decision up to you. And language coders passed along that power to you. Use it wisely.
And if you read until here, let me tell you I was lying a bit to you for the sake of oversimplification. The IEEE linked defines two kinds of NaNs, quiet ones and signaling ones. I have been talking about the quiet ones, the good guys. The signaling ones will cause exceptions in your software (overflowing, underflowing, etc).