What Is NaN: A Deeper Dive Into JavaScript's Implementation of the IEEE-754 Floating Point Standard
Updated on · 6 min read|NaN
, short for "Not a Number", is a special value in JavaScript and TypeScript (as well as many other programming languages) that represents an undefined or unrepresentable value resulting from an arithmetic operation. It is often used as a placeholder for a missing numerical value or as a way to signify an error.
However, what exactly is the type of NaN
in JavaScript? Is it a number, or is it a distinct data type? In this article, we will explore the intricacies of the NaN
data type, including its behavior in arithmetic operations, its relationship with other data types in JavaScript and beyond, and the results of the typeof
operator when applied to NaN
. We will also briefly discuss the usage of NaN
in TypeScript, as well as the built-in Number.isNaN()
and isNaN()
functions that can be used to test for the NaN
data type.
NaN data type in JavaScript
When exploring the NaN
data type in JavaScript, you may encounter a seemingly peculiar behavior. By typing typeof NaN
into your browser console, the result displayed is number
. This may initially appear to be an odd quirk of the JavaScript programming language. However, it is actually a standard feature of all programming languages that implement The IEEE Standard for Floating-Point Arithmetic (IEEE 754).
TypeScript, for example, doesn't have a separate type to signify NaN
values, therefore this code is valid:
tslet myNumber: number = NaN;
tslet myNumber: number = NaN;
Moreover, TypeScript doesn't have a special mechanism to check for NaN
values. To check if a value is NaN in TypeScript, you can use the Number.isNaN()
or isNaN()
functions, discussed in more detail below.
tslet myNumber: number = NaN; if (Number.isNaN(myNumber)) { console.log("myNumber is NaN"); } else { console.log("myNumber is not NaN"); }
tslet myNumber: number = NaN; if (Number.isNaN(myNumber)) { console.log("myNumber is NaN"); } else { console.log("myNumber is not NaN"); }
In other programming languages, such as Ruby, the NaN
value can also be represented as an instance of either Float
or BigDecimal
. Therefore, the NaN
data type is not unique to JavaScript.
To further understand the NaN
concept in JavaScript, we can refer to the ECMA-262, 13th edition, which is the ECMAScript Language Specification. According to section 4.4.24, the Number
type is defined as a "set of all possible Number values, including the special 'Not-a-Number' (NaN) value, positive infinity, and negative infinity." Subsequently, section 4.4.27 clarifies that NaN
is a "number value that is an IEEE 754-2019 'Not-a-Number' value."
What is the IEEE 754 standard?
First published in 1985, the primary goal of the IEEE 754 standard is to provide a consistent computational method using floating-point numbers across various processing environments, be it software, hardware, or a mix of both. Along with specifying formats and methods for floating-point arithmetic in computer programming environments, IEEE 754 also defines a set of special values. These special values include:
0
: Both-0
and+0
are distinct values, although they are equal. Here's an in-depth article explaining both zero values in JavaScript.- Denormalized number: A number that lies between the smallest normalized positive floating-point number and zero.
- Positive and negative
Infinity
: Values representing infinitely large positive or negative numbers. NaN
: A numeric data type that cannot be represented within the computing system.
IEEE 754 defines two types of NaN
- a quiet NaN
(qNaN
) and signaling NaN
(sNaN
). The primary difference between the two is that sNaN
will cause an exception when used in arithmetic operations, whereas qNaN
will not. In JavaScript, it appears that all NaN
values are quiet.
Additionally, the standard defines an interesting list of special operations and their results:
shellnumber ÷ 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
shellnumber ÷ 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
Most of the bits in the NaN
encoding are not used to store meaningful
information, which means they can be manipulated to store actual data - this
is known as NaN-tagging or
NaN-boxing. By using
NaN-tagging, programmers can add additional type information to values without
having to create new data types or use external metadata.
Testing for NaN values: Number.isNaN() vs isNaN()
JavaScript doesn't have a single NaN
value, in fact, according to ECMA-262, there are "18,437,736,874,454,810,627 (that is, 264 - 253 + 3) values, representing the double-precision 64-bit format IEEE 754-2019 values as specified in the IEEE Standard for Binary Floating-Point Arithmetic, except that the 9,007,199,254,740,990 (that is, 253 - 2) distinct 'Not-a-Number' values of the IEEE Standard are 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-defined; to ECMAScript code, all NaN values are indistinguishable from each other."
Since NaN
does not equal itself (in some programming languages, self-comparison is a widely used approach to test for NaNs), we need to use special methods such as Number.isNaN()
or isNaN()
to detect them.
It should be noted, that same-value equality methods, e.g. Object.is or
same-value-zero equality methods, e.g. the ones used by Map
and Set
for comparing key equality, determine whether two values are functionally identical in all contexts. These methods will produce true
when comparing NaN
to itself.
If you're interested in learning more about how to use Set
, in particular to remove duplicated items from an array, you might find this article helpful: Removing Duplicates with Map In JavaScript.
While both methods serve this purpose, they differ in their approach. Number.isNaN()
is more precise, as it only returns true if the value is currently NaN
and of the number
type. On the other hand, isNaN()
returns true
if the value is currently NaN
or if it will become NaN after being coerced to a numeric value. This distinction can lead to some unexpected results when using isNaN()
, as it may return true
for non-number values that are coerced to NaN
. In TypeScript, calling isNaN()
with an argument that is not of type number
will result in a type error, alerting the programmer to the potential issue. As a result, when testing for NaN
values, it is generally recommended to use Number.isNaN()
for its higher accuracy and stricter type checking.
To better illustrate the differences between these testing methods, here's a table comparing the output of Number.isNaN()
, isNaN()
, and typeof value === "number"
for various types of values.
Input value | Number.isNaN(value) | isNaN(value) | typeof value === "number" |
---|---|---|---|
NaN | true | true | true |
undefined | false | true | false |
null | false | false | false |
true | false | false | false |
"123" | false | false | false |
123 | false | false | true |
[] | false | false | false |
{} | false | true | false |
MDN provides a helpful explanation about testing against NaN.
Conclusion
NaN
, or "Not a Number," is a special value found in JavaScript and many other programming languages. It represents undefined or unrepresentable values resulting from arithmetic operations. Although it may seem counterintuitive for NaN
to be considered a number, it is actually a result of the widely adopted IEEE 754 standard for floating-point arithmetic.
Understanding the behavior and type of NaN
in JavaScript is important for developers working with numeric operations. To detect NaN
values, developers can use methods such as Number.isNaN()
and isNaN()
. These methods help ensure the accuracy and reliability of numeric operations in JavaScript.