I have a doubt about the existence of the famous NaN , I would like to know, what is it for? What is your "existential meaning"?
So far the only thing I have been able to understand based on things I have seen in books and videos is that in summary it would be a kind of Error indicator in mathematical operations that usually warns us that there is an "invalidity" (such as multiplying a string for an integer); In addition, its data type is numeric and its value is undefined and different from any other value.
I am right? is it used for something else?
I add a couple of quotes:
NaN means "Not a Number". When a function or mathematical operation in JavaScript cannot return a specific number, it returns the value NaN instead. It is a property of the global object, and a reference to Number.NaN
JavaScriptNotes for Professionals - GoalKicker.com - Pg. 13.
It is a special static numeric property, NaN, which is equivalent to the global NaN, and is equivalent to Not-a-Number. Anytime you try to use a value in a numeric operation that can't be parsed as a number, you'll get a NaN error.
Javascript Cookbook, Shelley Powers - Pg. 56
NaN is short for Not-a-Number and represents an illegal number. It uses the isNaN() function to determine if a number is legal or valid according to the ECMA-262 specification.
JavaScript Step by Step 2ed. Steve Suehring - Pg. 63
The context of the question would be only in terms of its application in JavaScript, since talking about programming in general, arithmetic, computing or other topics would make the question much broader and it would become a bit ambiguous; on the other hand, I understand that the existence of an "Error", "message" or "alert" may be logical for a situation such as the one that can arise when operating irrational numbers or taking mathematical operations out of the mathematical "context", but , how can NaN differ from "typical" Error messages?
Who has invented it?
NaN is not an invention of JavaScript. It is part of the IEEE-754 specification that defines how to represent real numbers in binary. All current implementations of real numbers used by different programming languages are based on this specification, such as types
float
(corresponding to IEEE-754 single-precision that uses 32 bits to represent reals) anddouble
(corresponding to IEEE-754 single-precision). extended precision, which uses 64 bits to represent the reals) of C. Not only C, but practically every current language uses this standard, because the hardware itself (the CPU's math processor) uses it. In the case of JavaScript, moreover, the language lacks the integer type (int
) so any JavaScript number is actually adouble
. We'll come back to JavaScript later. For now let's focus on IEEE-754.Leaving aside the problems of range and precision, which would be for another question and which deals with how it is possible to put all the reals (which are infinite, in fact an infinity of higher order than the infinity of the natural ones) in only 32 or 64 bits ( spoiler , you can't :-), and that's why weird things happen ) there is the additional problem that certain mathematical operations are defined for a subset of the reals, but not for all. I will focus on this problem here.
Why was it necessary?
The division, for example. It is possible to divide any two reals and the result will be another real, except in the case that the divisor is zero. In that case, the mathematical convention is adopted (for which there are good reasons I won't go into) that the result is "infinity" (or negative infinity if the numerator was negative).
"infinity" is not a real number. It is a concept. There is no real equal to infinity. However, if we have a "division" operation whose return type is
float
ordouble
, then we must provide one (32 or 64) bit combination to represent "infinity" (and one for "negative infinity"). The IEEE-754 standard provides for this.Infinity is not enough. There are other mathematical operations that have no definite result, and for which it makes no sense to say that "outputs infinity". For example, the square roots of any negative number have no result in real numbers. The same goes for the logarithm of zero, or any negative. Or with the arc sine of any number that is not between 0 and 1, etc. There are many examples of functions that are defined for only a subset of the reals. Trying to evaluate them on an element that is not in that subset should be treated as an error.
In languages that support exceptions, like JavaScript, Python, Java, etc. use could be made of this mechanism to signal the problem. In fact, Python for example does this, and when trying to calculate
math.log(-1)
the exception is obtainedValueError
. However, in other more primitive languages such as C or assembly, in which there are no exceptions, it is necessary to provide a certain combination of bits, similar to the case of infinity seen above, which represents that the operation is not valid. Or that "the result is not a real". Not a Number . NaN.IEEE-754 provides for this as well, and has a code (in fact a large number of them) to encode the "Not a number" concept. The CPU's math processor is the mechanism it uses, and what it returns as a result of illegal operations. C functions can also return that value (because it is a valid element of type
float
odouble
). Higher-level languages can choose to catch this result and raise an exception (as Python does), or "let it pass" and return NaN (as JavaScript does).What binary representation does it have?
The binary code that represents NaN in IEEE-754 single precision (32 bits) is x11111111xxxxxxxxxxxxxxxxxxxxxxxx, with each x being a bit that can be 1 or 0, except that the last 23 x cannot all be 0 (because in that case it would be representing infinity, the first bit being the sign). As we can see, the standard does not define a unique code for NaN, but in fact we have 2^(24)-2 possible representations. However, they are all considered equivalent, that is, conceptually there is "a single NaN" that can be represented in many ways.
In the case of double precision IEEE-754, there are even more possibilities, since in this format NaN is any bit pattern of the type x11111111111xxxx...xxx in which we have a first bit that can be 1 or 0 , another eleven bits that must be 1, and another 52 bits that can take any value as long as they are not all 0. With this pattern, 2^(53)-2 different codes can be generated.
Why so many different codes to represent NaN? The truth is that I don't know. Only one would do. My guess is that the designers of this standard couldn't find any other way to take advantage of the remaining 2^(24)-1 [or 2^(53)-1 in double precision] codes.
Why NaN != NaN?
Basically to avoid logic errors. If you have that
f(x) == f(y)
you might think thatx == y
. This is correct for many functions. For example, the square root. IfMath.sqrt(a) == Math.sqrt(b)
one could deduce that thena == b
. Indeed, if for exampleMath.sqrt(a) == 5
and the same forMath.sqrt(b)
, we can deduce that theya
areb
worth 25.But what if
a=-1
whileb=-4
? In that case as muchMath.sqrt(a)
asMath.sqrt(b)
will result inNaN
. If we accept thatNaN == NaN
, we could reach the erroneous conclusion thata==b
. Therefore by definitionNaN
it is always different fromNaN
(even if "below" are represented with the same binary code).In fact, once an operation has produced
NaN
, any other operation it usesNaN
as an argument shouldNaN
return in turn. If we were to allowNaN == NaN
that would imply that itNaN/NaN
should be 1, which would make it impossible to "propagate" the erroneous result between operations.rarities
NaN
is a value of typefloat
(odouble
) as already stated. Since JavaScript is the only numeric type it has, which it generically calls "number", it turns out toNaN
be a valid "number". Which is not without its grace.JavaScript uses
NaN
in contexts beyond those intended by the standard. For example, if you try to divide a number by a string, you will get an error, but of a different nature than the one inMath.log(-1)
. In the case of1/"cadena"
is a typing error. Not even the return type would be defined in this case. JavaScript decides that the result is of type "number", and since it can't give it a value, it gives it the valueNaN
.Finally, it could be thought that the same reasons put forward to defend that
NaN != NaN
would apply to "infinity", since ifa/0 == b/0
that does not implya == b
, but instead the IEEE-754 standard does not consider it that way. We can check it with JavaScript:NaN or exception?
It could be argued that an attempt to compute
Math.log(-1)
is an error that should throw an exception. Some languages do this by detecting that a result is NaN. However, the engineers who designed the IEEE-754 standard preferred to return a "special value" rather than generate a hardware exception, since that simplified the implementation at that time.I also insist on the fact that, as the behavior of is defined
NaN
, once an operation has producedNaN
, any other operation that uses the previous result will continue to result inNaN
. SpecificallyNaN - NaN = NaN
(another argument whyNaN!=NaN
, since the comparison is usually implemented at the hardware level with a subtraction). This "viral" behaviorNaN
is very reminiscent of how an exception propagates up from the function that raised it to the functions that called it.Also there may be cases where returning
NaN
is more useful than throwing an exception. A typical example is searching for zeros in a function, by a method similar to Newton 's . The problem is, given a function,f(x)
find a value ofx
for whichf(x)
is zero. Newton's method and others like it are based on trying a couple of values ofx
and if theyf(x)
are non-zero, using the result to better "tune" the next try. Without going into more detail, we can see that iff(x)
it is not defined for all possible itx
may be the case that we try ax
for which it is not defined. Throwing an exception would abort the method, while returningNaN
it would allow him to go ahead and try anotherx
. But in reality this justification seems flimsy to me. The same could be achieved (I think) by catching the exception and trying anotherx
.The true reason for the existence of
NaN
must be sought in its historical roots. At the time it was designed, this solution was much easier to implement with minimal modification to existing compilers and languages. For example, C, the most important language then (and perhaps even now) has no exceptions, and instead bases its error handling on functions returning "special values" to indicate that there was an error (-1 if the type returned isint
,NULL
if return type is pointer, andNaN
if return type isfloat
ordouble
).JavaScript seems to be the heir to this current, since
NaN
it is not the only case in which this language has chosen to return a "special" value instead of generating an exception. For example, accessing an array outside its bounds (which in other languages would generate an exception), causes in JS that the value obtained isundefined
:What is he for
NaN
?isNaN
NaN
, you already know that the value is a null or an empty String)Knowing this:
Why do they return false?
They return false because the value of an empty string
""
or anull
is converted to0
So we can operate with them:
So... where is he
NaN
?Well, as it says in the quote at the beginning of the question, if we parse these values before operating with them, we will obtain
NaN
The correct way to check with
isNaN
would be: