DEV Community

Cover image for What is the type of NaN?
Alex K.
Alex K.

Posted on • Originally published at claritydev.net

What is the type of NaN?

The article was originally posted on my personal blog.

I was recently answering an interesting question on Stack Overflow about the type of NaN.

this is what´s happening

typeof Number.parseInt('processed') prints 'number'.

enter image description here


But if Number.parseInt('processed') gives NaN.

enter image description here

enter image description here

And indeed if you type in your browser console typeof NaN === 'number' you'll get true. The comments to the answer made me realise that this is not another one of JavaScript quirks, but in fact a standard feature of all the programming languages that implement The IEEE Standard for Floating-Point Arithmetic (IEEE 754).

In Ruby, for example NaN can be either an instance of Float or BigDecimal.

And indeed, if we look at the ECMA-262, 10th edition, the ECMAScript Language Specification, section 4.3.21 states that number type represents a "set of all possible Number values including the special “Not-a-Number” (NaN) value, positive infinity, and negative infinity". A few subsections below, section 4.3.24 clarifies that NaN is a "number value that is an IEEE 754-2008 “Not-a-Number” value".

So what is this IEEE 754 standard?

First published in 1985, its main purpose is to provide a computational method with floating point numbers, which would have the same results independent of the environment where the processing is done, be it software, hardware or a mix of both. Together with specifying formats and methods for floating-point arithmetic in computer programming environments, IEEE 754 also defines a set of special values: 0 (-0 and +0 are distinct values, although they both are equal; here's an in-depth article about both zero values in JS), denormalised number, positive and negative Infinity, and NaN, which the standard describes as a numeric data type that cannot be represented within the computing system. In fact, IEEE 754 defines two types of NaN - a quiet NaN (qNaN) and a signalling NaN (sNaN). The most important difference between the two is that sNaN will cause an exception when used in arithmetic operations and qNaN won't. It seems like in JavaScript all the NaNs are quiet, at least I wasn't able to find any information to the contrary. 

Additionally, the standard defines an interesting list of special operations and their results:

number ÷ Infinity               = 0
number ÷ -Infinity              = -0

±Infinity × ±Infinity           = ±Infinity
±non zero number ÷ ±0           = ±Infinity
number × ±Infinity              = ±Infinity
Infinity + Infinity             = ±Infinity
Infinity – -Infinity            = +Infinity
-Infinity – Infinity            = Infinity
-Infinity + – Infinity          = Infinity

±0 ÷ ±0                         = NaN
±Infinity ÷ ±Infinity           = NaN
±Infinity × 0                   = NaN
NaN == NaN (also '===' in JS)   //False
Enter fullscreen mode Exit fullscreen mode
Testing for NaN values

JavaScript doesn't have a single NaN value, in fact, according to ECMA-262, there are "9007199254740990 (that is, 253 - 2) distinct “Not-a-Number” values of the IEEE Standard [...] represented in ECMAScript as a single special NaN value. In some implementations, external code might be able to detect a difference between various Not-a-Number values, but such behaviour is implementation-dependent; to ECMAScript code, all NaN values are indistinguishable from each other."

Because NaN doesn't equal to itself (and in fact in some programming languages self-comparison is a widely used approach to test for NaNs), we need to use a special Number.isNaN() or isNaN() methods to detect NaNs. The difference between the two is that isNaN() returns true if the value is currently NaN or it is going to be NaN after it's coerced to numeric value and Number.isNaN() only will return true if the value is currently NaN. Generally Number.isNaN() is more accurate since it also checks if the type of value is number. MDN has a handy explanation about testing against NaN.

Having "Not a Number" value to be a type of number is quite illogical, maybe a better name would be "Not a Real Number" or something along those lines. In this case, however, it's not a strange behaviour in JavaScript, but a general programming principle. 

Got any questions/comments or other kinds of feedback about this post? Let me know here in the comments or on Twitter.

Top comments (6)

Collapse
 
val_baca profile image
Valentin Baca • Edited

c/o "You Don't Know JS"

github.com/getify/You-Dont-Know-JS...

NaN isn't equal to itself. NaN is the only value in the whole language where that's true; every other value is always equal to itself.

So:

if (!Number.isNaN) {
    Number.isNaN = function(n) {
        return n !== n;
    };
}

Weird, huh? But it works!

Despite the (condescending) name, the YDKJS series is actually really great.

Collapse
 
vicoerv profile image
Vico

did the interpreter work like this.

if (token[0] == 'NaN') return false;

return token[0] == token[1];

just kidding

Collapse
 
clarity89 profile image
Alex K. • Edited

Haha, well it's more like each NaN has a different value under the hood, so technically they're not equal to each other.

Fun fact: since most of the bits in NaN encoding aren't used to store any meaningful information, they can be manipulated to store actual data - payload. This is called NaN-tagging or NaN-boxing and is mostly used for adding additional type encodings to values. Here's one interesting article about it.

Thread Thread
 
vicoerv profile image
Vico

wow thank you, never thought about that

Collapse
 
smlka profile image
Andrey Smolko • Edited

You are writing:

Having "Not a Number" value to be a type of number is quite illogical

Following explanation helped me to accept fact that NaN is number type=):

The special values such as infinity and NaN ensure that the floating-point arithmetic is algebraically completed

Collapse
 
aminnairi profile image
Amin

Very interesting article. I never knew there was a difference between isNaN and Number.isNaN. Thanks for sharing!